about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-07-11 17:10:09 +0000
committerbors <bors@rust-lang.org>2024-07-11 17:10:09 +0000
commita3d6efc9bcdc379e766735cc53e065d85a1755e9 (patch)
tree24923a8226aad3064a6c5739540c2d404d64f76e /src
parent45609a995e766d614da694d353f7aee03820b0f9 (diff)
parent62bbce2ad2b20d5cf1282da407d01de5c54161f1 (diff)
downloadrust-a3d6efc9bcdc379e766735cc53e065d85a1755e9.tar.gz
rust-a3d6efc9bcdc379e766735cc53e065d85a1755e9.zip
Auto merge of #17581 - lnicola:sync-from-rust, r=lnicola
minor: Sync from rust
Diffstat (limited to 'src')
-rw-r--r--src/bootstrap/Cargo.lock1
-rw-r--r--src/bootstrap/Cargo.toml1
-rw-r--r--src/bootstrap/bootstrap.py8
-rw-r--r--src/bootstrap/bootstrap_test.py19
-rw-r--r--src/bootstrap/defaults/config.dist.toml1
-rw-r--r--src/bootstrap/download-ci-llvm-stamp2
-rw-r--r--src/bootstrap/src/bin/rustc.rs44
-rw-r--r--src/bootstrap/src/bin/rustdoc.rs20
-rw-r--r--src/bootstrap/src/core/build_steps/clean.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs105
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs300
-rw-r--r--src/bootstrap/src/core/build_steps/doc.rs81
-rw-r--r--src/bootstrap/src/core/build_steps/format.rs56
-rw-r--r--src/bootstrap/src/core/build_steps/install.rs6
-rw-r--r--src/bootstrap/src/core/build_steps/llvm.rs33
-rw-r--r--src/bootstrap/src/core/build_steps/mod.rs1
-rw-r--r--src/bootstrap/src/core/build_steps/perf.rs35
-rw-r--r--src/bootstrap/src/core/build_steps/run.rs20
-rw-r--r--src/bootstrap/src/core/build_steps/setup.rs1
-rw-r--r--src/bootstrap/src/core/build_steps/suggest.rs16
-rw-r--r--src/bootstrap/src/core/build_steps/synthetic_targets.rs14
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs193
-rw-r--r--src/bootstrap/src/core/build_steps/tool.rs146
-rw-r--r--src/bootstrap/src/core/build_steps/toolstate.rs19
-rw-r--r--src/bootstrap/src/core/build_steps/vendor.rs11
-rw-r--r--src/bootstrap/src/core/builder.rs115
-rw-r--r--src/bootstrap/src/core/builder/tests.rs9
-rw-r--r--src/bootstrap/src/core/config/config.rs55
-rw-r--r--src/bootstrap/src/core/config/flags.rs6
-rw-r--r--src/bootstrap/src/core/download.rs18
-rw-r--r--src/bootstrap/src/core/metadata.rs23
-rw-r--r--src/bootstrap/src/core/sanity.rs16
-rw-r--r--src/bootstrap/src/lib.rs292
-rw-r--r--src/bootstrap/src/utils/bin_helpers.rs50
-rw-r--r--src/bootstrap/src/utils/cache.rs7
-rw-r--r--src/bootstrap/src/utils/cc_detect.rs8
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs5
-rw-r--r--src/bootstrap/src/utils/channel.rs14
-rw-r--r--src/bootstrap/src/utils/dylib.rs40
-rw-r--r--src/bootstrap/src/utils/exec.rs222
-rw-r--r--src/bootstrap/src/utils/helpers.rs39
-rw-r--r--src/bootstrap/src/utils/mod.rs2
-rw-r--r--src/bootstrap/src/utils/render_tests.rs17
-rw-r--r--src/bootstrap/src/utils/shared_helpers.rs112
-rw-r--r--src/bootstrap/src/utils/shared_helpers/tests.rs28
-rw-r--r--src/bootstrap/src/utils/tarball.rs42
-rw-r--r--src/ci/docker/README.md16
-rw-r--r--src/ci/docker/host-x86_64/disabled/riscv64gc-gnu/Dockerfile4
-rw-r--r--src/ci/docker/host-x86_64/dist-loongarch64-linux/Dockerfile27
-rw-r--r--src/ci/docker/host-x86_64/dist-loongarch64-musl/Dockerfile36
-rw-r--r--src/ci/docker/host-x86_64/dist-loongarch64-musl/loongarch64-unknown-linux-musl.defconfig15
-rw-r--r--src/ci/docker/host-x86_64/dist-various-2/Dockerfile2
-rwxr-xr-xsrc/ci/docker/host-x86_64/dist-x86_64-linux/build-gccjit.sh2
-rwxr-xr-xsrc/ci/docker/host-x86_64/dist-x86_64-netbsd/build-netbsd-toolchain.sh54
-rw-r--r--src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile2
-rw-r--r--src/ci/docker/host-x86_64/x86_64-fuchsia/Dockerfile (renamed from src/ci/docker/host-x86_64/x86_64-gnu-integration/Dockerfile)10
-rwxr-xr-xsrc/ci/docker/host-x86_64/x86_64-fuchsia/build-fuchsia.sh (renamed from src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh)10
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version2
-rw-r--r--src/ci/docker/host-x86_64/x86_64-rust-for-linux/Dockerfile (renamed from src/ci/docker/host-x86_64/rfl/Dockerfile)0
-rwxr-xr-xsrc/ci/docker/run.sh3
-rw-r--r--src/ci/docker/scripts/crosstool-ng-git.sh17
-rwxr-xr-xsrc/ci/docker/scripts/fuchsia-test-runner.py65
-rwxr-xr-xsrc/ci/github-actions/calculate-job-matrix.py14
-rw-r--r--src/ci/github-actions/jobs.yml27
-rwxr-xr-xsrc/ci/run.sh4
m---------src/doc/book0
m---------src/doc/edition-guide0
m---------src/doc/reference0
m---------src/doc/rust-by-example0
m---------src/doc/rustc-dev-guide0
-rw-r--r--src/doc/rustc/src/SUMMARY.md4
-rw-r--r--src/doc/rustc/src/codegen-options/index.md17
-rw-r--r--src/doc/rustc/src/lints/levels.md60
-rw-r--r--src/doc/rustc/src/platform-support.md23
-rw-r--r--src/doc/rustc/src/platform-support/esp-idf.md20
-rw-r--r--src/doc/rustc/src/platform-support/loongarch-linux.md139
-rw-r--r--src/doc/rustc/src/platform-support/loongarch-none.md56
-rw-r--r--src/doc/rustc/src/platform-support/powerpc-unknown-openbsd.md3
-rw-r--r--src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md2
-rw-r--r--src/doc/rustc/src/platform-support/xtensa.md6
-rw-r--r--src/doc/rustdoc/src/advanced-features.md3
-rw-r--r--src/doc/style-guide/src/nightly.md12
-rw-r--r--src/doc/unstable-book/src/compiler-flags/patchable-function-entry.md24
-rw-r--r--src/doc/unstable-book/src/compiler-flags/verbose-asm.md70
-rw-r--r--src/doc/unstable-book/src/language-features/c-unwind.md26
-rw-r--r--src/doc/unstable-book/src/language-features/intrinsics.md4
-rw-r--r--src/doc/unstable-book/src/library-features/sort-internals.md5
-rw-r--r--src/etc/completions/x.py.fish35
-rw-r--r--src/etc/completions/x.py.ps142
-rw-r--r--src/etc/completions/x.py.sh115
-rw-r--r--src/etc/completions/x.py.zsh49
-rwxr-xr-xsrc/etc/htmldocck.py84
-rw-r--r--src/etc/natvis/intrinsic.natvis26
-rwxr-xr-xsrc/etc/pre-push.sh2
-rw-r--r--src/librustdoc/Cargo.toml1
-rw-r--r--src/librustdoc/clean/mod.rs32
-rw-r--r--src/librustdoc/clean/simplify.rs2
-rw-r--r--src/librustdoc/clean/types.rs24
-rw-r--r--src/librustdoc/fold.rs4
-rw-r--r--src/librustdoc/html/markdown.rs111
-rw-r--r--src/librustdoc/html/render/print_item.rs23
-rw-r--r--src/librustdoc/html/render/write_shared.rs3
-rw-r--r--src/librustdoc/html/static/js/search.js18
-rw-r--r--src/librustdoc/json/conversions.rs33
-rw-r--r--src/librustdoc/lint.rs13
-rw-r--r--src/librustdoc/passes/calculate_doc_coverage.rs1
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs32
-rw-r--r--src/librustdoc/passes/collect_trait_impls.rs1
-rw-r--r--src/librustdoc/passes/lint.rs2
-rw-r--r--src/librustdoc/passes/lint/bare_urls.rs40
-rw-r--r--src/librustdoc/passes/lint/check_code_block_syntax.rs1
-rw-r--r--src/librustdoc/passes/lint/html_tags.rs7
-rw-r--r--src/librustdoc/passes/lint/redundant_explicit_links.rs16
-rw-r--r--src/librustdoc/passes/lint/unportable_markdown.rs152
-rw-r--r--src/librustdoc/passes/propagate_doc_cfg.rs1
-rw-r--r--src/librustdoc/passes/strip_priv_imports.rs1
-rw-r--r--src/librustdoc/passes/strip_private.rs1
-rw-r--r--src/librustdoc/passes/stripper.rs1
-rw-r--r--src/librustdoc/visit.rs4
m---------src/llvm-project0
-rw-r--r--src/rustdoc-json-types/lib.rs6
-rw-r--r--src/tools/build-manifest/README.md2
-rw-r--r--src/tools/build-manifest/src/main.rs2
-rw-r--r--src/tools/build_helper/src/util.rs28
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/.github/workflows/lintcheck.yml118
-rw-r--r--src/tools/clippy/CHANGELOG.md5
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md5
-rw-r--r--src/tools/clippy/book/src/usage.md2
-rw-r--r--src/tools/clippy/clippy_config/src/conf.rs3
-rw-r--r--src/tools/clippy/clippy_config/src/msrvs.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/allow_attributes.rs74
-rw-r--r--src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/assigning_clones.rs82
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/mod.rs69
-rw-r--r--src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/cognitive_complexity.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/copies.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs52
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/mod.rs32
-rw-r--r--src/tools/clippy/clippy_lints/src/empty_with_brackets.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs75
-rw-r--r--src/tools/clippy/clippy_lints/src/float_literal.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/future_not_send.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_hasher.rs40
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_return.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mod.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_float_methods.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs111
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_utils.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/mod.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/single_match.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs238
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs54
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_collect.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs90
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_doc.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_else.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_for_each.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_if.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/octal_escapes.rs158
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/float_cmp.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/ranges.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_slicing.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/string_patterns.rs25
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unconditional_recursion.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs102
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/zero_div_zero.rs1
-rw-r--r--src/tools/clippy/clippy_utils/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils.rs10
-rw-r--r--src/tools/clippy/clippy_utils/src/check_proc_macro.rs84
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs64
-rw-r--r--src/tools/clippy/clippy_utils/src/higher.rs63
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs168
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/paths.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs3
-rw-r--r--src/tools/clippy/clippy_utils/src/source.rs201
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs24
-rw-r--r--src/tools/clippy/lintcheck/Cargo.toml15
-rw-r--r--src/tools/clippy/lintcheck/README.md6
-rw-r--r--src/tools/clippy/lintcheck/src/config.rs46
-rw-r--r--src/tools/clippy/lintcheck/src/json.rs122
-rw-r--r--src/tools/clippy/lintcheck/src/main.rs261
-rw-r--r--src/tools/clippy/lintcheck/src/popular-crates.rs65
-rw-r--r--src/tools/clippy/lintcheck/src/popular_crates.rs52
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/src/driver.rs2
-rw-r--r--src/tools/clippy/tests/integration.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/Cargo.stderr32
-rw-r--r--src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.rs2
-rw-r--r--src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs2
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs1
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr20
-rw-r--r--src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.default.stderr74
-rw-r--r--src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr94
-rw-r--r--src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs1
-rw-r--r--src/tools/clippy/tests/ui/allow_attributes.fixed13
-rw-r--r--src/tools/clippy/tests/ui/allow_attributes.rs13
-rw-r--r--src/tools/clippy/tests/ui/allow_attributes.stderr20
-rw-r--r--src/tools/clippy/tests/ui/allow_attributes_without_reason.rs13
-rw-r--r--src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr29
-rw-r--r--src/tools/clippy/tests/ui/arithmetic_side_effects.rs4
-rw-r--r--src/tools/clippy/tests/ui/arithmetic_side_effects.stderr260
-rw-r--r--src/tools/clippy/tests/ui/assigning_clones.fixed56
-rw-r--r--src/tools/clippy/tests/ui/assigning_clones.rs56
-rw-r--r--src/tools/clippy/tests/ui/async_yields_async.fixed1
-rw-r--r--src/tools/clippy/tests/ui/async_yields_async.rs1
-rw-r--r--src/tools/clippy/tests/ui/async_yields_async.stderr12
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/external_consts.rs1
-rw-r--r--src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr2
-rw-r--r--src/tools/clippy/tests/ui/boxed_local.rs1
-rw-r--r--src/tools/clippy/tests/ui/boxed_local.stderr8
-rw-r--r--src/tools/clippy/tests/ui/cast.rs3
-rw-r--r--src/tools/clippy/tests/ui/cast.stderr184
-rw-r--r--src/tools/clippy/tests/ui/cast_lossless_float.fixed2
-rw-r--r--src/tools/clippy/tests/ui/cast_lossless_float.rs2
-rw-r--r--src/tools/clippy/tests/ui/cast_lossless_float.stderr26
-rw-r--r--src/tools/clippy/tests/ui/cast_nan_to_int.rs2
-rw-r--r--src/tools/clippy/tests/ui/cast_nan_to_int.stderr12
-rw-r--r--src/tools/clippy/tests/ui/cast_size.32bit.stderr52
-rw-r--r--src/tools/clippy/tests/ui/cast_size.64bit.stderr50
-rw-r--r--src/tools/clippy/tests/ui/cast_size.rs13
-rw-r--r--src/tools/clippy/tests/ui/cfg_attr_cargo_clippy.stderr18
-rw-r--r--src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs1
-rw-r--r--src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr54
-rw-r--r--src/tools/clippy/tests/ui/copy_iterator.rs1
-rw-r--r--src/tools/clippy/tests/ui/copy_iterator.stderr2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-12284.rs10
-rw-r--r--src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr2
-rw-r--r--src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.stderr1
-rw-r--r--src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed1
-rw-r--r--src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs1
-rw-r--r--src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr56
-rw-r--r--src/tools/clippy/tests/ui/derive_partial_eq_without_eq.fixed1
-rw-r--r--src/tools/clippy/tests/ui/derive_partial_eq_without_eq.rs1
-rw-r--r--src/tools/clippy/tests/ui/derive_partial_eq_without_eq.stderr26
-rw-r--r--src/tools/clippy/tests/ui/endian_bytes.rs2
-rw-r--r--src/tools/clippy/tests/ui/endian_bytes.stderr172
-rw-r--r--src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs1
-rw-r--r--src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr12
-rw-r--r--src/tools/clippy/tests/ui/field_scoped_visibility_modifiers.rs21
-rw-r--r--src/tools/clippy/tests/ui/field_scoped_visibility_modifiers.stderr28
-rw-r--r--src/tools/clippy/tests/ui/float_cmp.rs2
-rw-r--r--src/tools/clippy/tests/ui/float_cmp.stderr12
-rw-r--r--src/tools/clippy/tests/ui/float_equality_without_abs.rs3
-rw-r--r--src/tools/clippy/tests/ui/float_equality_without_abs.stderr22
-rw-r--r--src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs4
-rw-r--r--src/tools/clippy/tests/ui/floating_point_exp.fixed2
-rw-r--r--src/tools/clippy/tests/ui/floating_point_exp.rs2
-rw-r--r--src/tools/clippy/tests/ui/floating_point_exp.stderr10
-rw-r--r--src/tools/clippy/tests/ui/floating_point_log.fixed2
-rw-r--r--src/tools/clippy/tests/ui/floating_point_log.rs2
-rw-r--r--src/tools/clippy/tests/ui/floating_point_log.stderr58
-rw-r--r--src/tools/clippy/tests/ui/floating_point_powf.fixed2
-rw-r--r--src/tools/clippy/tests/ui/floating_point_powf.rs2
-rw-r--r--src/tools/clippy/tests/ui/floating_point_powf.stderr62
-rw-r--r--src/tools/clippy/tests/ui/implicit_return.fixed14
-rw-r--r--src/tools/clippy/tests/ui/implicit_return.rs14
-rw-r--r--src/tools/clippy/tests/ui/implicit_return.stderr32
-rw-r--r--src/tools/clippy/tests/ui/let_unit.fixed1
-rw-r--r--src/tools/clippy/tests/ui/let_unit.rs1
-rw-r--r--src/tools/clippy/tests/ui/let_unit.stderr8
-rw-r--r--src/tools/clippy/tests/ui/lossy_float_literal.fixed24
-rw-r--r--src/tools/clippy/tests/ui/lossy_float_literal.rs24
-rw-r--r--src/tools/clippy/tests/ui/lossy_float_literal.stderr22
-rw-r--r--src/tools/clippy/tests/ui/macro_use_imports.fixed1
-rw-r--r--src/tools/clippy/tests/ui/macro_use_imports.rs1
-rw-r--r--src/tools/clippy/tests/ui/macro_use_imports.stderr8
-rw-r--r--src/tools/clippy/tests/ui/macro_use_imports_expect.rs1
-rw-r--r--src/tools/clippy/tests/ui/manual_float_methods.rs2
-rw-r--r--src/tools/clippy/tests/ui/manual_float_methods.stderr12
-rw-r--r--src/tools/clippy/tests/ui/manual_inspect.fixed174
-rw-r--r--src/tools/clippy/tests/ui/manual_inspect.rs186
-rw-r--r--src/tools/clippy/tests/ui/manual_inspect.stderr182
-rw-r--r--src/tools/clippy/tests/ui/manual_non_exhaustive_enum.rs1
-rw-r--r--src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr8
-rw-r--r--src/tools/clippy/tests/ui/manual_pattern_char_comparison.fixed12
-rw-r--r--src/tools/clippy/tests/ui/manual_pattern_char_comparison.rs12
-rw-r--r--src/tools/clippy/tests/ui/manual_pattern_char_comparison.stderr8
-rw-r--r--src/tools/clippy/tests/ui/manual_split_once.stderr10
-rw-r--r--src/tools/clippy/tests/ui/manual_unwrap_or.fixed52
-rw-r--r--src/tools/clippy/tests/ui/manual_unwrap_or.rs60
-rw-r--r--src/tools/clippy/tests/ui/manual_unwrap_or.stderr40
-rw-r--r--src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed23
-rw-r--r--src/tools/clippy/tests/ui/manual_unwrap_or_default.rs23
-rw-r--r--src/tools/clippy/tests/ui/match_result_ok.fixed7
-rw-r--r--src/tools/clippy/tests/ui/match_result_ok.rs7
-rw-r--r--src/tools/clippy/tests/ui/match_result_ok.stderr6
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed176
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs3
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr109
-rw-r--r--src/tools/clippy/tests/ui/modulo_arithmetic_float.rs27
-rw-r--r--src/tools/clippy/tests/ui/modulo_arithmetic_float.stderr70
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.fixed1
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.rs1
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.stderr56
-rw-r--r--src/tools/clippy/tests/ui/needless_collect_indirect.stderr2
-rw-r--r--src/tools/clippy/tests/ui/needless_late_init.stderr2
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs1
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr68
-rw-r--r--src/tools/clippy/tests/ui/needless_return.fixed1
-rw-r--r--src/tools/clippy/tests/ui/needless_return.rs1
-rw-r--r--src/tools/clippy/tests/ui/needless_return.stderr108
-rw-r--r--src/tools/clippy/tests/ui/nonminimal_bool.rs2
-rw-r--r--src/tools/clippy/tests/ui/nonminimal_bool.stderr58
-rw-r--r--src/tools/clippy/tests/ui/octal_escapes.rs27
-rw-r--r--src/tools/clippy/tests/ui/octal_escapes.stderr180
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.fixed3
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.rs3
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.stderr50
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.fixed2
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.stderr8
-rw-r--r--src/tools/clippy/tests/ui/overly_complex_bool_expr.fixed1
-rw-r--r--src/tools/clippy/tests/ui/overly_complex_bool_expr.rs1
-rw-r--r--src/tools/clippy/tests/ui/overly_complex_bool_expr.stderr20
-rw-r--r--src/tools/clippy/tests/ui/ptr_arg.rs1
-rw-r--r--src/tools/clippy/tests/ui/ptr_arg.stderr48
-rw-r--r--src/tools/clippy/tests/ui/redundant_clone.fixed1
-rw-r--r--src/tools/clippy/tests/ui/redundant_clone.rs1
-rw-r--r--src/tools/clippy/tests/ui/redundant_clone.stderr60
-rw-r--r--src/tools/clippy/tests/ui/ref_binding_to_reference.rs1
-rw-r--r--src/tools/clippy/tests/ui/ref_binding_to_reference.stderr14
-rw-r--r--src/tools/clippy/tests/ui/same_name_method.rs1
-rw-r--r--src/tools/clippy/tests/ui/same_name_method.stderr24
-rw-r--r--src/tools/clippy/tests/ui/significant_drop_tightening.stderr2
-rw-r--r--src/tools/clippy/tests/ui/tabs_in_doc_comments.stderr48
-rw-r--r--src/tools/clippy/tests/ui/transmute.rs30
-rw-r--r--src/tools/clippy/tests/ui/transmute.stderr116
-rw-r--r--src/tools/clippy/tests/ui/transmute_float_to_int.fixed12
-rw-r--r--src/tools/clippy/tests/ui/transmute_float_to_int.rs12
-rw-r--r--src/tools/clippy/tests/ui/transmute_float_to_int.stderr12
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_clippy_cfg.stderr56
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_min_or_max.fixed67
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_min_or_max.rs67
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_min_or_max.stderr107
-rw-r--r--src/tools/clippy/tests/ui/unsafe_derive_deserialize.rs1
-rw-r--r--src/tools/clippy/tests/ui/unsafe_derive_deserialize.stderr8
-rw-r--r--src/tools/clippy/tests/ui/unused_rounding.fixed2
-rw-r--r--src/tools/clippy/tests/ui/unused_rounding.rs2
-rw-r--r--src/tools/clippy/tests/ui/unused_rounding.stderr10
-rw-r--r--src/tools/clippy/tests/ui/used_underscore_binding.rs2
-rw-r--r--src/tools/clippy/triagebot.toml3
-rw-r--r--src/tools/clippy/util/gh-pages/index.html34
-rw-r--r--src/tools/clippy/util/gh-pages/script.js33
-rw-r--r--src/tools/compiletest/src/command-list.rs232
-rw-r--r--src/tools/compiletest/src/header.rs272
-rw-r--r--src/tools/compiletest/src/header/needs.rs26
-rw-r--r--src/tools/compiletest/src/header/tests.rs20
-rw-r--r--src/tools/compiletest/src/runtest.rs9
-rw-r--r--src/tools/generate-windows-sys/Cargo.toml2
-rw-r--r--src/tools/generate-windows-sys/src/main.rs1
-rw-r--r--src/tools/jsondocck/src/cache.rs2
-rw-r--r--src/tools/jsondocck/src/main.rs4
-rw-r--r--src/tools/jsondoclint/src/validator.rs4
-rw-r--r--src/tools/linkchecker/main.rs2
-rw-r--r--src/tools/miri/.github/workflows/ci.yml87
-rw-r--r--src/tools/miri/.github/workflows/setup/action.yml52
-rw-r--r--src/tools/miri/README.md18
-rw-r--r--src/tools/miri/build.rs6
-rw-r--r--src/tools/miri/cargo-miri/src/phases.rs6
-rwxr-xr-xsrc/tools/miri/miri3
-rw-r--r--src/tools/miri/miri-script/src/commands.rs6
-rw-r--r--src/tools/miri/miri-script/src/util.rs3
-rw-r--r--src/tools/miri/miri.bat3
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/alloc_addresses/mod.rs2
-rw-r--r--src/tools/miri/src/alloc_bytes.rs28
-rw-r--r--src/tools/miri/src/bin/miri.rs7
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs10
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs19
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs4
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs41
-rw-r--r--src/tools/miri/src/concurrency/thread.rs3
-rw-r--r--src/tools/miri/src/diagnostics.rs33
-rw-r--r--src/tools/miri/src/eval.rs15
-rw-r--r--src/tools/miri/src/helpers.rs67
-rw-r--r--src/tools/miri/src/lib.rs2
-rw-r--r--src/tools/miri/src/machine.rs6
-rw-r--r--src/tools/miri/src/shims/alloc.rs12
-rw-r--r--src/tools/miri/src/shims/backtrace.rs2
-rw-r--r--src/tools/miri/src/shims/foreign_items.rs43
-rw-r--r--src/tools/miri/src/shims/panic.rs6
-rw-r--r--src/tools/miri/src/shims/time.rs2
-rw-r--r--src/tools/miri/src/shims/unix/env.rs6
-rw-r--r--src/tools/miri/src/shims/unix/fd.rs43
-rw-r--r--src/tools/miri/src/shims/unix/foreign_items.rs25
-rw-r--r--src/tools/miri/src/shims/unix/fs.rs9
-rw-r--r--src/tools/miri/src/shims/unix/socket.rs2
-rw-r--r--src/tools/miri/src/shims/windows/foreign_items.rs30
-rw-r--r--src/tools/miri/src/shims/windows/handle.rs4
-rw-r--r--src/tools/miri/src/shims/x86/avx.rs11
-rw-r--r--src/tools/miri/src/shims/x86/avx2.rs35
-rw-r--r--src/tools/miri/src/shims/x86/bmi.rs108
-rw-r--r--src/tools/miri/src/shims/x86/mod.rs157
-rw-r--r--src/tools/miri/src/shims/x86/sse2.rs16
-rw-r--r--src/tools/miri/src/shims/x86/ssse3.rs10
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_main_terminate.stderr2
-rw-r--r--src/tools/miri/tests/fail-dep/libc/aligned_alloc_size_zero_leak.stderr2
-rw-r--r--src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.stderr4
-rw-r--r--src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.stderr2
-rw-r--r--src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_leak.stderr2
-rw-r--r--src/tools/miri/tests/fail/alloc/too_large.rs10
-rw-r--r--src/tools/miri/tests/fail/alloc/too_large.stderr15
-rw-r--r--src/tools/miri/tests/fail/extern-type-field-offset.stderr4
-rw-r--r--src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind1.rs2
-rw-r--r--src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs2
-rw-r--r--src/tools/miri/tests/fail/intrinsic_fallback_is_spec.rs2
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr7
-rw-r--r--src/tools/miri/tests/fail/memleak.stderr2
-rw-r--r--src/tools/miri/tests/fail/memleak_no_backtrace.rs2
-rw-r--r--src/tools/miri/tests/fail/memleak_no_backtrace.stderr4
-rw-r--r--src/tools/miri/tests/fail/memleak_rc.32bit.stderr25
-rw-r--r--src/tools/miri/tests/fail/memleak_rc.rs2
-rw-r--r--src/tools/miri/tests/fail/memleak_rc.stderr (renamed from src/tools/miri/tests/fail/memleak_rc.64bit.stderr)4
-rw-r--r--src/tools/miri/tests/fail/panic/bad_unwind.rs2
-rw-r--r--src/tools/miri/tests/fail/shims/fs/isolated_file.stderr4
-rw-r--r--src/tools/miri/tests/fail/tail_calls/cc-mismatch.rs10
-rw-r--r--src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr25
-rw-r--r--src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs17
-rw-r--r--src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr17
-rw-r--r--src/tools/miri/tests/fail/terminate-terminator.rs2
-rw-r--r--src/tools/miri/tests/fail/tls_macro_leak.stderr2
-rw-r--r--src/tools/miri/tests/fail/tls_static_leak.stderr2
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/protector-write-lazy.rs35
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/protector-write-lazy.stderr27
-rw-r--r--src/tools/miri/tests/fail/unwind-action-terminate.rs2
-rw-r--r--src/tools/miri/tests/panic/function_calls/exported_symbol_good_unwind.rs2
-rw-r--r--src/tools/miri/tests/pass-dep/concurrency/tls_pthread_drop_order.rs6
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-fs.rs26
-rw-r--r--src/tools/miri/tests/pass/async-closure.rs21
-rw-r--r--src/tools/miri/tests/pass/async-closure.stdout6
-rw-r--r--src/tools/miri/tests/pass/box.stack.stderr7
-rw-r--r--src/tools/miri/tests/pass/extern_types.stack.stderr7
-rw-r--r--src/tools/miri/tests/pass/function_pointers.rs3
-rw-r--r--src/tools/miri/tests/pass/intptrcast.rs4
-rw-r--r--src/tools/miri/tests/pass/issues/issue-91636.rs1
-rw-r--r--src/tools/miri/tests/pass/issues/issue-miri-3680.rs21
-rw-r--r--src/tools/miri/tests/pass/packed_struct.rs2
-rw-r--r--src/tools/miri/tests/pass/shims/fs.rs4
-rw-r--r--src/tools/miri/tests/pass/shims/io.rs2
-rw-r--r--src/tools/miri/tests/pass/shims/x86/intrinsics-x86-adx.rs70
-rw-r--r--src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs5
-rw-r--r--src/tools/miri/tests/pass/shims/x86/intrinsics-x86-bmi.rs216
-rw-r--r--src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr7
-rw-r--r--src/tools/miri/tests/pass/tail_call.rs39
-rw-r--r--src/tools/miri/tests/pass/tls/tls_macro_drop.rs102
-rw-r--r--src/tools/miri/tests/pass/tls/tls_macro_drop.stack.stdout3
-rw-r--r--src/tools/miri/tests/pass/tls/tls_macro_drop.tree.stdout3
-rw-r--r--src/tools/miri/tests/pass/tls/tls_macro_drop_single_thread.rs36
-rw-r--r--src/tools/miri/tests/pass/tls/tls_macro_drop_single_thread.stderr3
-rw-r--r--src/tools/miri/tests/pass/tls/tls_macro_drop_single_thread.stdout2
-rw-r--r--src/tools/miri/tests/pass/tls/win_tls_callback.rs16
-rw-r--r--src/tools/miri/tests/pass/tls/win_tls_callback.stderr1
-rw-r--r--src/tools/miri/tests/pass/vecdeque.rs4
-rw-r--r--src/tools/remote-test-client/src/main.rs2
-rw-r--r--src/tools/run-make-support/Cargo.toml2
-rw-r--r--src/tools/run-make-support/src/command.rs19
-rw-r--r--src/tools/run-make-support/src/diff/mod.rs34
-rw-r--r--src/tools/run-make-support/src/fs_wrapper.rs20
-rw-r--r--src/tools/run-make-support/src/lib.rs97
-rw-r--r--src/tools/run-make-support/src/llvm.rs27
-rw-r--r--src/tools/run-make-support/src/rustc.rs56
-rw-r--r--src/tools/run-make-support/src/rustdoc.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs1
-rw-r--r--src/tools/rust-analyzer/crates/salsa/salsa-macros/src/database_storage.rs8
-rw-r--r--src/tools/rust-analyzer/crates/stdx/src/anymap.rs71
-rw-r--r--src/tools/rust-analyzer/rust-version2
-rw-r--r--src/tools/rust-installer/src/combiner.rs9
-rw-r--r--src/tools/rust-installer/src/generator.rs9
-rw-r--r--src/tools/rust-installer/src/tarballer.rs18
-rw-r--r--src/tools/rustc-perf-wrapper/Cargo.toml7
-rw-r--r--src/tools/rustc-perf-wrapper/README.md3
-rw-r--r--src/tools/rustc-perf-wrapper/src/config.rs45
-rw-r--r--src/tools/rustc-perf-wrapper/src/main.rs130
-rw-r--r--src/tools/rustfmt/.github/workflows/integration.yml1
-rw-r--r--src/tools/rustfmt/CHANGELOG.md107
-rw-r--r--src/tools/rustfmt/Cargo.lock61
-rw-r--r--src/tools/rustfmt/Cargo.toml11
-rw-r--r--src/tools/rustfmt/Configurations.md39
-rw-r--r--src/tools/rustfmt/Contributing.md2
-rw-r--r--src/tools/rustfmt/Processes.md2
-rw-r--r--src/tools/rustfmt/build.rs4
-rw-r--r--src/tools/rustfmt/check_diff/.gitignore1
-rw-r--r--src/tools/rustfmt/check_diff/Cargo.lock237
-rw-r--r--src/tools/rustfmt/check_diff/Cargo.toml9
-rw-r--r--src/tools/rustfmt/check_diff/src/main.rs25
-rwxr-xr-xsrc/tools/rustfmt/ci/check_diff.sh46
-rwxr-xr-xsrc/tools/rustfmt/ci/integration.sh2
-rw-r--r--src/tools/rustfmt/config_proc_macro/src/attrs.rs6
-rw-r--r--src/tools/rustfmt/docs/index.html32
-rw-r--r--src/tools/rustfmt/intellij.md2
-rw-r--r--src/tools/rustfmt/rust-toolchain2
-rw-r--r--src/tools/rustfmt/src/attr.rs16
-rw-r--r--src/tools/rustfmt/src/bin/main.rs17
-rw-r--r--src/tools/rustfmt/src/cargo-fmt/main.rs9
-rw-r--r--src/tools/rustfmt/src/cargo-fmt/test/mod.rs22
-rw-r--r--src/tools/rustfmt/src/comment.rs49
-rw-r--r--src/tools/rustfmt/src/config/config_type.rs22
-rw-r--r--src/tools/rustfmt/src/config/mod.rs21
-rw-r--r--src/tools/rustfmt/src/config/options.rs28
-rw-r--r--src/tools/rustfmt/src/config/style_edition.rs70
-rw-r--r--src/tools/rustfmt/src/emitter/checkstyle.rs14
-rw-r--r--src/tools/rustfmt/src/emitter/diff.rs2
-rw-r--r--src/tools/rustfmt/src/emitter/json.rs12
-rw-r--r--src/tools/rustfmt/src/expr.rs33
-rw-r--r--src/tools/rustfmt/src/format-diff/main.rs18
-rw-r--r--src/tools/rustfmt/src/formatting.rs2
-rw-r--r--src/tools/rustfmt/src/formatting/generated.rs7
-rw-r--r--src/tools/rustfmt/src/ignore_path.rs18
-rw-r--r--src/tools/rustfmt/src/imports.rs4
-rw-r--r--src/tools/rustfmt/src/items.rs49
-rw-r--r--src/tools/rustfmt/src/lib.rs16
-rw-r--r--src/tools/rustfmt/src/macros.rs19
-rw-r--r--src/tools/rustfmt/src/matches.rs18
-rw-r--r--src/tools/rustfmt/src/overflow.rs43
-rw-r--r--src/tools/rustfmt/src/parse/macros/lazy_static.rs1
-rw-r--r--src/tools/rustfmt/src/parse/macros/mod.rs6
-rw-r--r--src/tools/rustfmt/src/parse/session.rs10
-rw-r--r--src/tools/rustfmt/src/source_file.rs2
-rw-r--r--src/tools/rustfmt/src/spanned.rs9
-rw-r--r--src/tools/rustfmt/src/test/configuration_snippet.rs26
-rw-r--r--src/tools/rustfmt/src/test/mod.rs24
-rw-r--r--src/tools/rustfmt/src/types.rs82
-rw-r--r--src/tools/rustfmt/src/visitor.rs2
-rw-r--r--src/tools/rustfmt/tests/config/issue-5801-v1.toml3
-rw-r--r--src/tools/rustfmt/tests/config/issue-5801-v2.toml3
-rw-r--r--src/tools/rustfmt/tests/mod-resolver/skip-files-issue-5065/main.rs2
-rw-r--r--src/tools/rustfmt/tests/rustfmt/main.rs25
-rw-r--r--src/tools/rustfmt/tests/source/arrow_in_comments/arrow_in_single_comment.rs10
-rw-r--r--src/tools/rustfmt/tests/source/arrow_in_comments/multiple_arrows.rs14
-rw-r--r--src/tools/rustfmt/tests/source/configs/format_generated_files/false_with_generated_marker_line_search_limit.rs10
-rw-r--r--src/tools/rustfmt/tests/source/configs/format_generated_files/false_with_marker_out_scope_size.rs10
-rw-r--r--src/tools/rustfmt/tests/source/configs/format_generated_files/false_with_zero_search_limit.rs9
-rw-r--r--src/tools/rustfmt/tests/source/configs/format_generated_files/true_with_marker_in_scope_size.rs10
-rw-r--r--src/tools/rustfmt/tests/source/configs/format_generated_files/true_with_marker_not_in_header.rs9
-rw-r--r--src/tools/rustfmt/tests/source/issue-3805.rs65
-rw-r--r--src/tools/rustfmt/tests/source/issue-5801/attribute_unexpectedly_wraps_before_max_width.rs8
-rw-r--r--src/tools/rustfmt/tests/source/issue-5801/comment_unexpectedly_wraps_before_max_width.rs17
-rw-r--r--src/tools/rustfmt/tests/source/issue-5987/two.rs13
-rw-r--r--src/tools/rustfmt/tests/source/issue-6059/repro.rs3
-rw-r--r--src/tools/rustfmt/tests/source/issue-6147/case_rustfmt_v1.rs20
-rw-r--r--src/tools/rustfmt/tests/source/issue-6147/case_rustfmt_v2.rs20
-rw-r--r--src/tools/rustfmt/tests/source/issue_5912.rs15
-rw-r--r--src/tools/rustfmt/tests/source/let_else.rs6
-rw-r--r--src/tools/rustfmt/tests/source/no_arg_with_commnet.rs2
-rw-r--r--src/tools/rustfmt/tests/source/precise-capturing.rs9
-rw-r--r--src/tools/rustfmt/tests/target/arrow_in_comments/arrow_in_single_comment.rs10
-rw-r--r--src/tools/rustfmt/tests/target/arrow_in_comments/multiple_arrows.rs19
-rw-r--r--src/tools/rustfmt/tests/target/configs/format_generated_files/false_with_generated_marker_line_search_limit.rs10
-rw-r--r--src/tools/rustfmt/tests/target/configs/format_generated_files/false_with_marker_out_scope_size.rs8
-rw-r--r--src/tools/rustfmt/tests/target/configs/format_generated_files/false_with_zero_search_limit.rs8
-rw-r--r--src/tools/rustfmt/tests/target/configs/format_generated_files/true_with_marker_in_scope_size.rs8
-rw-r--r--src/tools/rustfmt/tests/target/configs/format_generated_files/true_with_marker_not_in_header.rs7
-rw-r--r--src/tools/rustfmt/tests/target/impl.rs5
-rw-r--r--src/tools/rustfmt/tests/target/issue-3805.rs94
-rw-r--r--src/tools/rustfmt/tests/target/issue-5801/attribute_does_not_wrap_within_max_width.rs8
-rw-r--r--src/tools/rustfmt/tests/target/issue-5801/attribute_unexpectedly_wraps_before_max_width.rs16
-rw-r--r--src/tools/rustfmt/tests/target/issue-5801/comment_does_not_wrap_within_max_width.rs16
-rw-r--r--src/tools/rustfmt/tests/target/issue-5801/comment_unexpectedly_wraps_before_max_width.rs18
-rw-r--r--src/tools/rustfmt/tests/target/issue-5885.rs3
-rw-r--r--src/tools/rustfmt/tests/target/issue-5987/one.rs13
-rw-r--r--src/tools/rustfmt/tests/target/issue-5987/two.rs12
-rw-r--r--src/tools/rustfmt/tests/target/issue-6059/additional.rs6
-rw-r--r--src/tools/rustfmt/tests/target/issue-6059/repro.rs3
-rw-r--r--src/tools/rustfmt/tests/target/issue-6105.rs1
-rw-r--r--src/tools/rustfmt/tests/target/issue-6147/case_rustfmt_v1.rs20
-rw-r--r--src/tools/rustfmt/tests/target/issue-6147/case_rustfmt_v2.rs20
-rw-r--r--src/tools/rustfmt/tests/target/issue_5912.rs15
-rw-r--r--src/tools/rustfmt/tests/target/issue_6069.rs3
-rw-r--r--src/tools/rustfmt/tests/target/issue_6158.rs7
-rw-r--r--src/tools/rustfmt/tests/target/issue_6159.rs3
-rw-r--r--src/tools/rustfmt/tests/target/let_else.rs6
-rw-r--r--src/tools/rustfmt/tests/target/no_arg_with_commnet.rs2
-rw-r--r--src/tools/rustfmt/tests/target/precise-capturing.rs55
-rw-r--r--src/tools/rustfmt/tests/target/return-type-notation.rs10
-rw-r--r--src/tools/rustfmt/tests/target/unsafe_attributes.rs34
-rw-r--r--src/tools/rustfmt/tests/target/unsafe_extern_blocks.rs18
-rw-r--r--src/tools/tidy/Cargo.toml3
-rw-r--r--src/tools/tidy/config/requirements.in5
-rw-r--r--src/tools/tidy/config/requirements.txt108
-rw-r--r--src/tools/tidy/config/ruff.toml23
-rw-r--r--src/tools/tidy/src/allowed_run_make_makefiles.txt82
-rw-r--r--src/tools/tidy/src/deps.rs15
-rw-r--r--src/tools/tidy/src/ext_tool_checks.rs144
-rw-r--r--src/tools/tidy/src/extdeps.rs15
-rw-r--r--src/tools/tidy/src/features.rs14
-rw-r--r--src/tools/tidy/src/fluent_period.rs84
-rw-r--r--src/tools/tidy/src/lib.rs1
-rw-r--r--src/tools/tidy/src/main.rs1
-rw-r--r--src/tools/tidy/src/pal.rs2
-rw-r--r--src/tools/tidy/src/run_make_tests.rs2
-rw-r--r--src/tools/tidy/src/style.rs8
-rw-r--r--src/tools/tidy/src/target_policy.rs3
-rw-r--r--src/tools/tidy/src/ui_tests.rs3
616 files changed, 11745 insertions, 4900 deletions
diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock
index 9c24742cff1..c095127da14 100644
--- a/src/bootstrap/Cargo.lock
+++ b/src/bootstrap/Cargo.lock
@@ -54,7 +54,6 @@ dependencies = [
  "junction",
  "libc",
  "object",
- "once_cell",
  "opener",
  "pretty_assertions",
  "semver",
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index 32dd3efa7a6..df7b5b88193 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -49,7 +49,6 @@ home = "0.5"
 ignore = "0.4"
 libc = "0.2"
 object = { version = "0.32", default-features = false, features = ["archive", "coff", "read_core", "unaligned"] }
-once_cell = "1.19"
 opener = "0.5"
 semver = "1.0"
 serde = "1.0"
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 9861121aac0..7e47b373ff9 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -617,6 +617,9 @@ class RustBuild(object):
                 self.fix_bin_or_dylib("{}/bin/rustdoc".format(bin_root))
                 self.fix_bin_or_dylib("{}/libexec/rust-analyzer-proc-macro-srv".format(bin_root))
                 lib_dir = "{}/lib".format(bin_root)
+                rustlib_bin_dir = "{}/rustlib/{}/bin".format(lib_dir, self.build)
+                self.fix_bin_or_dylib("{}/rust-lld".format(rustlib_bin_dir))
+                self.fix_bin_or_dylib("{}/gcc-ld/ld.lld".format(rustlib_bin_dir))
                 for lib in os.listdir(lib_dir):
                     # .so is not necessarily the suffix, there can be version numbers afterwards.
                     if ".so" in lib:
@@ -731,12 +734,9 @@ class RustBuild(object):
 
         patchelf = "{}/bin/patchelf".format(nix_deps_dir)
         rpath_entries = [
-            # Relative default, all binary and dynamic libraries we ship
-            # appear to have this (even when `../lib` is redundant).
-            "$ORIGIN/../lib",
             os.path.join(os.path.realpath(nix_deps_dir), "lib")
         ]
-        patchelf_args = ["--set-rpath", ":".join(rpath_entries)]
+        patchelf_args = ["--add-rpath", ":".join(rpath_entries)]
         if ".so" not in fname:
             # Finally, set the correct .interp for binaries
             with open("{}/nix-support/dynamic-linker".format(nix_deps_dir)) as dynamic_linker:
diff --git a/src/bootstrap/bootstrap_test.py b/src/bootstrap/bootstrap_test.py
index 6da410ed2f2..706f2c5bf07 100644
--- a/src/bootstrap/bootstrap_test.py
+++ b/src/bootstrap/bootstrap_test.py
@@ -138,6 +138,25 @@ class BuildBootstrap(unittest.TestCase):
         if env is None:
             env = {}
 
+        # This test ends up invoking build_bootstrap_cmd, which searches for
+        # the Cargo binary and errors out if it cannot be found. This is not a
+        # problem in most cases, but there is a scenario where it would cause
+        # the test to fail.
+        #
+        # When a custom local Cargo is configured in config.toml (with the
+        # build.cargo setting), no Cargo is downloaded to any location known by
+        # bootstrap, and bootstrap relies on that setting to find it.
+        #
+        # In this test though we are not using the config.toml of the caller:
+        # we are generating a blank one instead. If we don't set build.cargo in
+        # it, the test will have no way to find Cargo, failing the test.
+        cargo_bin = os.environ.get("BOOTSTRAP_TEST_CARGO_BIN")
+        if cargo_bin is not None:
+            configure_args += ["--set", "build.cargo=" + cargo_bin]
+        rustc_bin = os.environ.get("BOOTSTRAP_TEST_RUSTC_BIN")
+        if rustc_bin is not None:
+            configure_args += ["--set", "build.rustc=" + rustc_bin]
+
         env = env.copy()
         env["PATH"] = os.environ["PATH"]
 
diff --git a/src/bootstrap/defaults/config.dist.toml b/src/bootstrap/defaults/config.dist.toml
index d06930f2b9d..d4feffe0227 100644
--- a/src/bootstrap/defaults/config.dist.toml
+++ b/src/bootstrap/defaults/config.dist.toml
@@ -16,6 +16,7 @@ download-ci-llvm = false
 # Make sure they don't get set when installing from source.
 channel = "nightly"
 download-rustc = false
+lld = true
 # Build the llvm-bitcode-linker
 llvm-bitcode-linker = true
 
diff --git a/src/bootstrap/download-ci-llvm-stamp b/src/bootstrap/download-ci-llvm-stamp
index e4dbd3a13fe..258a0347451 100644
--- a/src/bootstrap/download-ci-llvm-stamp
+++ b/src/bootstrap/download-ci-llvm-stamp
@@ -1,4 +1,4 @@
 Change this file to make users of the `download-ci-llvm` configuration download
 a new version of LLVM from CI, even if the LLVM submodule hasn’t changed.
 
-Last change is for: https://github.com/rust-lang/rust/pull/125141
+Last change is for: https://github.com/rust-lang/rust/pull/126298
diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs
index d2274199177..46e845f77ae 100644
--- a/src/bootstrap/src/bin/rustc.rs
+++ b/src/bootstrap/src/bin/rustc.rs
@@ -20,26 +20,24 @@ use std::path::{Path, PathBuf};
 use std::process::{Child, Command};
 use std::time::Instant;
 
-use dylib_util::{dylib_path, dylib_path_var, exe};
+use shared_helpers::{
+    dylib_path, dylib_path_var, exe, maybe_dump, parse_rustc_stage, parse_rustc_verbose,
+    parse_value_from_args,
+};
 
-#[path = "../utils/bin_helpers.rs"]
-mod bin_helpers;
-
-#[path = "../utils/dylib.rs"]
-mod dylib_util;
+#[path = "../utils/shared_helpers.rs"]
+mod shared_helpers;
 
 fn main() {
     let orig_args = env::args_os().skip(1).collect::<Vec<_>>();
     let mut args = orig_args.clone();
-    let arg =
-        |name| orig_args.windows(2).find(|args| args[0] == name).and_then(|args| args[1].to_str());
 
-    let stage = bin_helpers::parse_rustc_stage();
-    let verbose = bin_helpers::parse_rustc_verbose();
+    let stage = parse_rustc_stage();
+    let verbose = parse_rustc_verbose();
 
     // Detect whether or not we're a build script depending on whether --target
     // is passed (a bit janky...)
-    let target = arg("--target");
+    let target = parse_value_from_args(&orig_args, "--target");
     let version = args.iter().find(|w| &**w == "-vV");
 
     // Use a different compiler for build scripts, since there may not yet be a
@@ -102,7 +100,7 @@ fn main() {
     cmd.args(&args).env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
 
     // Get the name of the crate we're compiling, if any.
-    let crate_name = arg("--crate-name");
+    let crate_name = parse_value_from_args(&orig_args, "--crate-name");
 
     if let Some(crate_name) = crate_name {
         if let Some(target) = env::var_os("RUSTC_TIME") {
@@ -143,10 +141,11 @@ fn main() {
             cmd.arg("-C").arg("panic=abort");
         }
 
+        let crate_type = parse_value_from_args(&orig_args, "--crate-type");
         // `-Ztls-model=initial-exec` must not be applied to proc-macros, see
         // issue https://github.com/rust-lang/rust/issues/100530
         if env::var("RUSTC_TLS_MODEL_INITIAL_EXEC").is_ok()
-            && arg("--crate-type") != Some("proc-macro")
+            && crate_type != Some("proc-macro")
             && !matches!(crate_name, Some("proc_macro2" | "quote" | "syn" | "synstructure"))
         {
             cmd.arg("-Ztls-model=initial-exec");
@@ -251,7 +250,7 @@ fn main() {
         eprintln!("{prefix} libdir: {libdir:?}");
     }
 
-    bin_helpers::maybe_dump(format!("stage{stage}-rustc"), &cmd);
+    maybe_dump(format!("stage{stage}-rustc"), &cmd);
 
     let start = Instant::now();
     let (child, status) = {
@@ -318,9 +317,7 @@ fn format_rusage_data(child: Child) -> Option<String> {
 
     use windows::{
         Win32::Foundation::HANDLE,
-        Win32::System::ProcessStatus::{
-            K32GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS, PROCESS_MEMORY_COUNTERS_EX,
-        },
+        Win32::System::ProcessStatus::{K32GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS},
         Win32::System::Threading::GetProcessTimes,
         Win32::System::Time::FileTimeToSystemTime,
     };
@@ -332,6 +329,7 @@ fn format_rusage_data(child: Child) -> Option<String> {
     let mut kernel_filetime = Default::default();
     let mut kernel_time = Default::default();
     let mut memory_counters = PROCESS_MEMORY_COUNTERS::default();
+    let memory_counters_size = std::mem::size_of_val(&memory_counters);
 
     unsafe {
         GetProcessTimes(
@@ -348,15 +346,9 @@ fn format_rusage_data(child: Child) -> Option<String> {
 
     // Unlike on Linux with RUSAGE_CHILDREN, this will only return memory information for the process
     // with the given handle and none of that process's children.
-    unsafe {
-        K32GetProcessMemoryInfo(
-            handle,
-            &mut memory_counters,
-            std::mem::size_of::<PROCESS_MEMORY_COUNTERS_EX>() as u32,
-        )
-    }
-    .ok()
-    .ok()?;
+    unsafe { K32GetProcessMemoryInfo(handle, &mut memory_counters, memory_counters_size as u32) }
+        .ok()
+        .ok()?;
 
     // Guide on interpreting these numbers:
     // https://docs.microsoft.com/en-us/windows/win32/psapi/process-memory-usage-information
diff --git a/src/bootstrap/src/bin/rustdoc.rs b/src/bootstrap/src/bin/rustdoc.rs
index b4d1415189c..ba6b0c2dbda 100644
--- a/src/bootstrap/src/bin/rustdoc.rs
+++ b/src/bootstrap/src/bin/rustdoc.rs
@@ -6,19 +6,19 @@ use std::env;
 use std::path::PathBuf;
 use std::process::Command;
 
-use dylib_util::{dylib_path, dylib_path_var};
+use shared_helpers::{
+    dylib_path, dylib_path_var, maybe_dump, parse_rustc_stage, parse_rustc_verbose,
+    parse_value_from_args,
+};
 
-#[path = "../utils/bin_helpers.rs"]
-mod bin_helpers;
-
-#[path = "../utils/dylib.rs"]
-mod dylib_util;
+#[path = "../utils/shared_helpers.rs"]
+mod shared_helpers;
 
 fn main() {
     let args = env::args_os().skip(1).collect::<Vec<_>>();
 
-    let stage = bin_helpers::parse_rustc_stage();
-    let verbose = bin_helpers::parse_rustc_verbose();
+    let stage = parse_rustc_stage();
+    let verbose = parse_rustc_verbose();
 
     let rustdoc = env::var_os("RUSTDOC_REAL").expect("RUSTDOC_REAL was not set");
     let libdir = env::var_os("RUSTDOC_LIBDIR").expect("RUSTDOC_LIBDIR was not set");
@@ -26,7 +26,7 @@ fn main() {
 
     // Detect whether or not we're a build script depending on whether --target
     // is passed (a bit janky...)
-    let target = args.windows(2).find(|w| &*w[0] == "--target").and_then(|w| w[1].to_str());
+    let target = parse_value_from_args(&args, "--target");
 
     let mut dylib_path = dylib_path();
     dylib_path.insert(0, PathBuf::from(libdir.clone()));
@@ -62,7 +62,7 @@ fn main() {
     cmd.arg("-Zunstable-options");
     cmd.arg("--check-cfg=cfg(bootstrap)");
 
-    bin_helpers::maybe_dump(format!("stage{stage}-rustdoc"), &cmd);
+    maybe_dump(format!("stage{stage}-rustdoc"), &cmd);
 
     if verbose > 1 {
         eprintln!(
diff --git a/src/bootstrap/src/core/build_steps/clean.rs b/src/bootstrap/src/core/build_steps/clean.rs
index a81d6403013..a4be6bc56c5 100644
--- a/src/bootstrap/src/core/build_steps/clean.rs
+++ b/src/bootstrap/src/core/build_steps/clean.rs
@@ -85,7 +85,7 @@ macro_rules! clean_crate_tree {
 
                 // NOTE: doesn't use `run_cargo` because we don't want to save a stamp file,
                 // and doesn't use `stream_cargo` to avoid passing `--message-format` which `clean` doesn't accept.
-                builder.run(&mut cargo);
+                cargo.run(builder);
             }
         }
     )+ }
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index cc5b0073213..11a7a404535 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -27,8 +27,9 @@ use crate::core::builder::crate_description;
 use crate::core::builder::Cargo;
 use crate::core::builder::{Builder, Kind, PathSet, RunConfig, ShouldRun, Step, TaskPath};
 use crate::core::config::{DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection};
+use crate::utils::exec::command;
 use crate::utils::helpers::{
-    exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, output, symlink_dir, t, up_to_date,
+    exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, symlink_dir, t, up_to_date,
 };
 use crate::LLVM_TOOLS;
 use crate::{CLang, Compiler, DependencyType, GitRepo, Mode};
@@ -160,9 +161,10 @@ impl Step for Std {
             // This check is specific to testing std itself; see `test::Std` for more details.
             && !self.force_recompile
         {
+            let sysroot = builder.ensure(Sysroot { compiler, force_recompile: false });
             cp_rustc_component_to_ci_sysroot(
                 builder,
-                compiler,
+                &sysroot,
                 builder.config.ci_rust_std_contents(),
             );
             return;
@@ -771,20 +773,19 @@ impl Step for StartupObjects {
             let src_file = &src_dir.join(file.to_string() + ".rs");
             let dst_file = &dst_dir.join(file.to_string() + ".o");
             if !up_to_date(src_file, dst_file) {
-                let mut cmd = Command::new(&builder.initial_rustc);
+                let mut cmd = command(&builder.initial_rustc);
                 cmd.env("RUSTC_BOOTSTRAP", "1");
                 if !builder.local_rebuild {
                     // a local_rebuild compiler already has stage1 features
                     cmd.arg("--cfg").arg("bootstrap");
                 }
-                builder.run(
-                    cmd.arg("--target")
-                        .arg(target.rustc_target_arg())
-                        .arg("--emit=obj")
-                        .arg("-o")
-                        .arg(dst_file)
-                        .arg(src_file),
-                );
+                cmd.arg("--target")
+                    .arg(target.rustc_target_arg())
+                    .arg("--emit=obj")
+                    .arg("-o")
+                    .arg(dst_file)
+                    .arg(src_file)
+                    .run(builder);
             }
 
             let target = sysroot_dir.join((*file).to_string() + ".o");
@@ -796,12 +797,7 @@ impl Step for StartupObjects {
     }
 }
 
-fn cp_rustc_component_to_ci_sysroot(
-    builder: &Builder<'_>,
-    compiler: Compiler,
-    contents: Vec<String>,
-) {
-    let sysroot = builder.ensure(Sysroot { compiler, force_recompile: false });
+fn cp_rustc_component_to_ci_sysroot(builder: &Builder<'_>, sysroot: &Path, contents: Vec<String>) {
     let ci_rustc_dir = builder.config.ci_rustc_dir();
 
     for file in contents {
@@ -880,13 +876,7 @@ impl Step for Rustc {
         // NOTE: the ABI of the beta compiler is different from the ABI of the downloaded compiler,
         // so its artifacts can't be reused.
         if builder.download_rustc() && compiler.stage != 0 {
-            // Copy the existing artifacts instead of rebuilding them.
-            // NOTE: this path is only taken for tools linking to rustc-dev (including ui-fulldeps tests).
-            cp_rustc_component_to_ci_sysroot(
-                builder,
-                compiler,
-                builder.config.ci_rustc_dev_contents(),
-            );
+            builder.ensure(Sysroot { compiler, force_recompile: false });
             return compiler.stage;
         }
 
@@ -1290,15 +1280,21 @@ fn needs_codegen_config(run: &RunConfig<'_>) -> bool {
 pub(crate) const CODEGEN_BACKEND_PREFIX: &str = "rustc_codegen_";
 
 fn is_codegen_cfg_needed(path: &TaskPath, run: &RunConfig<'_>) -> bool {
-    if path.path.to_str().unwrap().contains(CODEGEN_BACKEND_PREFIX) {
+    let path = path.path.to_str().unwrap();
+
+    let is_explicitly_called = |p| -> bool { run.builder.paths.contains(p) };
+    let should_enforce = run.builder.kind == Kind::Dist || run.builder.kind == Kind::Install;
+
+    if path.contains(CODEGEN_BACKEND_PREFIX) {
         let mut needs_codegen_backend_config = true;
         for backend in run.builder.config.codegen_backends(run.target) {
-            if path.path.to_str().unwrap().ends_with(&(CODEGEN_BACKEND_PREFIX.to_owned() + backend))
-            {
+            if path.ends_with(&(CODEGEN_BACKEND_PREFIX.to_owned() + backend)) {
                 needs_codegen_backend_config = false;
             }
         }
-        if needs_codegen_backend_config {
+        if (is_explicitly_called(&PathBuf::from(path)) || should_enforce)
+            && needs_codegen_backend_config
+        {
             run.builder.info(
                 "WARNING: no codegen-backends config matched the requested path to build a codegen backend. \
                 HELP: add backend to codegen-backends in config.toml.",
@@ -1491,10 +1487,10 @@ pub fn compiler_file(
     if builder.config.dry_run() {
         return PathBuf::new();
     }
-    let mut cmd = Command::new(compiler);
+    let mut cmd = command(compiler);
     cmd.args(builder.cflags(target, GitRepo::Rustc, c));
     cmd.arg(format!("-print-file-name={file}"));
-    let out = output(&mut cmd);
+    let out = cmd.capture_stdout().run(builder).stdout();
     PathBuf::from(out.trim())
 }
 
@@ -1627,31 +1623,44 @@ impl Step for Sysroot {
         let sysroot_lib_rustlib_src_rust = sysroot_lib_rustlib_src.join("rust");
         if let Err(e) = symlink_dir(&builder.config, &builder.src, &sysroot_lib_rustlib_src_rust) {
             eprintln!(
-                "WARNING: creating symbolic link `{}` to `{}` failed with {}",
+                "ERROR: creating symbolic link `{}` to `{}` failed with {}",
                 sysroot_lib_rustlib_src_rust.display(),
                 builder.src.display(),
                 e,
             );
             if builder.config.rust_remap_debuginfo {
                 eprintln!(
-                    "WARNING: some `tests/ui` tests will fail when lacking `{}`",
+                    "ERROR: some `tests/ui` tests will fail when lacking `{}`",
                     sysroot_lib_rustlib_src_rust.display(),
                 );
             }
+            build_helper::exit!(1);
         }
-        // Same for the rustc-src component.
-        let sysroot_lib_rustlib_rustcsrc = sysroot.join("lib/rustlib/rustc-src");
-        t!(fs::create_dir_all(&sysroot_lib_rustlib_rustcsrc));
-        let sysroot_lib_rustlib_rustcsrc_rust = sysroot_lib_rustlib_rustcsrc.join("rust");
-        if let Err(e) =
-            symlink_dir(&builder.config, &builder.src, &sysroot_lib_rustlib_rustcsrc_rust)
-        {
-            eprintln!(
-                "WARNING: creating symbolic link `{}` to `{}` failed with {}",
-                sysroot_lib_rustlib_rustcsrc_rust.display(),
-                builder.src.display(),
-                e,
+
+        // Unlike rust-src component, we have to handle rustc-src a bit differently.
+        // When using CI rustc, we copy rustc-src component from its sysroot,
+        // otherwise we handle it in a similar way what we do for rust-src above.
+        if builder.download_rustc() {
+            cp_rustc_component_to_ci_sysroot(
+                builder,
+                &sysroot,
+                builder.config.ci_rustc_dev_contents(),
             );
+        } else {
+            let sysroot_lib_rustlib_rustcsrc = sysroot.join("lib/rustlib/rustc-src");
+            t!(fs::create_dir_all(&sysroot_lib_rustlib_rustcsrc));
+            let sysroot_lib_rustlib_rustcsrc_rust = sysroot_lib_rustlib_rustcsrc.join("rust");
+            if let Err(e) =
+                symlink_dir(&builder.config, &builder.src, &sysroot_lib_rustlib_rustcsrc_rust)
+            {
+                eprintln!(
+                    "ERROR: creating symbolic link `{}` to `{}` failed with {}",
+                    sysroot_lib_rustlib_rustcsrc_rust.display(),
+                    builder.src.display(),
+                    e,
+                );
+                build_helper::exit!(1);
+            }
         }
 
         sysroot
@@ -1826,7 +1835,8 @@ impl Step for Assemble {
             let llvm::LlvmResult { llvm_config, .. } =
                 builder.ensure(llvm::Llvm { target: target_compiler.host });
             if !builder.config.dry_run() && builder.config.llvm_tools_enabled {
-                let llvm_bin_dir = output(Command::new(llvm_config).arg("--bindir"));
+                let llvm_bin_dir =
+                    command(llvm_config).capture_stdout().arg("--bindir").run(builder).stdout();
                 let llvm_bin_dir = Path::new(llvm_bin_dir.trim());
 
                 // Since we've already built the LLVM tools, install them to the sysroot.
@@ -2070,7 +2080,7 @@ pub fn stream_cargo(
     tail_args: Vec<String>,
     cb: &mut dyn FnMut(CargoMessage<'_>),
 ) -> bool {
-    let mut cargo = Command::from(cargo);
+    let mut cargo = cargo.into_cmd().command;
     // Instruct Cargo to give us json messages on stdout, critically leaving
     // stderr as piped so we can get those pretty colors.
     let mut message_format = if builder.config.json_output {
@@ -2151,8 +2161,7 @@ pub fn strip_debug(builder: &Builder<'_>, target: TargetSelection, path: &Path)
     }
 
     let previous_mtime = FileTime::from_last_modification_time(&path.metadata().unwrap());
-    // NOTE: `output` will propagate any errors here.
-    output(Command::new("strip").arg("--strip-debug").arg(path));
+    command("strip").capture().arg("--strip-debug").arg(path).run(builder);
 
     // After running `strip`, we have to set the file modification time to what it was before,
     // otherwise we risk Cargo invalidating its fingerprint and rebuilding the world next time
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index 54136d2aebd..7bc5405e92f 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -14,7 +14,6 @@ use std::ffi::OsStr;
 use std::fs;
 use std::io::Write;
 use std::path::{Path, PathBuf};
-use std::process::Command;
 
 use object::read::archive::ArchiveFile;
 use object::BinaryFormat;
@@ -26,8 +25,9 @@ use crate::core::build_steps::tool::{self, Tool};
 use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
 use crate::core::config::TargetSelection;
 use crate::utils::channel::{self, Info};
+use crate::utils::exec::{command, BootstrapCommand};
 use crate::utils::helpers::{
-    exe, is_dylib, move_file, output, t, target_supports_cranelift_backend, timeit,
+    exe, is_dylib, move_file, t, target_supports_cranelift_backend, timeit,
 };
 use crate::utils::tarball::{GeneratedTarball, OverlayKind, Tarball};
 use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS};
@@ -180,9 +180,9 @@ fn make_win_dist(
     }
 
     //Ask gcc where it keeps its stuff
-    let mut cmd = Command::new(builder.cc(target));
+    let mut cmd = command(builder.cc(target));
     cmd.arg("-print-search-dirs");
-    let gcc_out = output(&mut cmd);
+    let gcc_out = cmd.capture_stdout().run(builder).stdout();
 
     let mut bin_path: Vec<_> = env::split_paths(&env::var_os("PATH").unwrap_or_default()).collect();
     let mut lib_path = Vec::new();
@@ -665,6 +665,10 @@ impl Step for Std {
     }
 }
 
+/// Tarball containing the compiler that gets downloaded and used by
+/// `rust.download-rustc`.
+///
+/// (Don't confuse this with [`RustDev`], without the `c`!)
 #[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
 pub struct RustcDev {
     pub compiler: Compiler,
@@ -1014,12 +1018,12 @@ impl Step for PlainSourceTarball {
             // perhaps it should be removed in favor of making `dist` perform the `vendor` step?
 
             // Ensure we have all submodules from src and other directories checked out.
-            for submodule in builder.get_all_submodules() {
+            for submodule in build_helper::util::parse_gitmodules(&builder.src) {
                 builder.update_submodule(Path::new(submodule));
             }
 
             // Vendor all Cargo dependencies
-            let mut cmd = Command::new(&builder.initial_cargo);
+            let mut cmd = command(&builder.initial_cargo);
             cmd.arg("vendor")
                 .arg("--versioned-dirs")
                 .arg("--sync")
@@ -1057,7 +1061,7 @@ impl Step for PlainSourceTarball {
             }
 
             let config = if !builder.config.dry_run() {
-                t!(String::from_utf8(t!(cmd.output()).stdout))
+                cmd.capture().run(builder).stdout()
             } else {
                 String::new()
             };
@@ -1595,14 +1599,14 @@ impl Step for Extended {
             let _ = fs::remove_dir_all(&pkg);
 
             let pkgbuild = |component: &str| {
-                let mut cmd = Command::new("pkgbuild");
+                let mut cmd = command("pkgbuild");
                 cmd.arg("--identifier")
                     .arg(format!("org.rust-lang.{}", component))
                     .arg("--scripts")
                     .arg(pkg.join(component))
                     .arg("--nopayload")
                     .arg(pkg.join(component).with_extension("pkg"));
-                builder.run(&mut cmd);
+                cmd.run(builder);
             };
 
             let prepare = |name: &str| {
@@ -1632,7 +1636,7 @@ impl Step for Extended {
             builder.create_dir(&pkg.join("res"));
             builder.create(&pkg.join("res/LICENSE.txt"), &license);
             builder.install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), 0o644);
-            let mut cmd = Command::new("productbuild");
+            let mut cmd = command("productbuild");
             cmd.arg("--distribution")
                 .arg(xform(&etc.join("pkg/Distribution.xml")))
                 .arg("--resources")
@@ -1645,7 +1649,7 @@ impl Step for Extended {
                 .arg("--package-path")
                 .arg(&pkg);
             let _time = timeit(builder);
-            builder.run(&mut cmd);
+            cmd.run(builder);
         }
 
         if target.is_windows() {
@@ -1699,168 +1703,159 @@ impl Step for Extended {
             let light = wix.join("bin/light.exe");
 
             let heat_flags = ["-nologo", "-gg", "-sfrag", "-srd", "-sreg"];
-            builder.run(
-                Command::new(&heat)
+            command(&heat)
+                .current_dir(&exe)
+                .arg("dir")
+                .arg("rustc")
+                .args(heat_flags)
+                .arg("-cg")
+                .arg("RustcGroup")
+                .arg("-dr")
+                .arg("Rustc")
+                .arg("-var")
+                .arg("var.RustcDir")
+                .arg("-out")
+                .arg(exe.join("RustcGroup.wxs"))
+                .run(builder);
+            if built_tools.contains("rust-docs") {
+                command(&heat)
                     .current_dir(&exe)
                     .arg("dir")
-                    .arg("rustc")
+                    .arg("rust-docs")
                     .args(heat_flags)
                     .arg("-cg")
-                    .arg("RustcGroup")
+                    .arg("DocsGroup")
                     .arg("-dr")
-                    .arg("Rustc")
+                    .arg("Docs")
                     .arg("-var")
-                    .arg("var.RustcDir")
+                    .arg("var.DocsDir")
                     .arg("-out")
-                    .arg(exe.join("RustcGroup.wxs")),
-            );
-            if built_tools.contains("rust-docs") {
-                builder.run(
-                    Command::new(&heat)
-                        .current_dir(&exe)
-                        .arg("dir")
-                        .arg("rust-docs")
-                        .args(heat_flags)
-                        .arg("-cg")
-                        .arg("DocsGroup")
-                        .arg("-dr")
-                        .arg("Docs")
-                        .arg("-var")
-                        .arg("var.DocsDir")
-                        .arg("-out")
-                        .arg(exe.join("DocsGroup.wxs"))
-                        .arg("-t")
-                        .arg(etc.join("msi/squash-components.xsl")),
-                );
+                    .arg(exe.join("DocsGroup.wxs"))
+                    .arg("-t")
+                    .arg(etc.join("msi/squash-components.xsl"))
+                    .run(builder);
             }
-            builder.run(
-                Command::new(&heat)
+            command(&heat)
+                .current_dir(&exe)
+                .arg("dir")
+                .arg("cargo")
+                .args(heat_flags)
+                .arg("-cg")
+                .arg("CargoGroup")
+                .arg("-dr")
+                .arg("Cargo")
+                .arg("-var")
+                .arg("var.CargoDir")
+                .arg("-out")
+                .arg(exe.join("CargoGroup.wxs"))
+                .arg("-t")
+                .arg(etc.join("msi/remove-duplicates.xsl"))
+                .run(builder);
+            command(&heat)
+                .current_dir(&exe)
+                .arg("dir")
+                .arg("rust-std")
+                .args(heat_flags)
+                .arg("-cg")
+                .arg("StdGroup")
+                .arg("-dr")
+                .arg("Std")
+                .arg("-var")
+                .arg("var.StdDir")
+                .arg("-out")
+                .arg(exe.join("StdGroup.wxs"))
+                .run(builder);
+            if built_tools.contains("rust-analyzer") {
+                command(&heat)
                     .current_dir(&exe)
                     .arg("dir")
-                    .arg("cargo")
+                    .arg("rust-analyzer")
                     .args(heat_flags)
                     .arg("-cg")
-                    .arg("CargoGroup")
+                    .arg("RustAnalyzerGroup")
                     .arg("-dr")
-                    .arg("Cargo")
+                    .arg("RustAnalyzer")
                     .arg("-var")
-                    .arg("var.CargoDir")
+                    .arg("var.RustAnalyzerDir")
                     .arg("-out")
-                    .arg(exe.join("CargoGroup.wxs"))
+                    .arg(exe.join("RustAnalyzerGroup.wxs"))
                     .arg("-t")
-                    .arg(etc.join("msi/remove-duplicates.xsl")),
-            );
-            builder.run(
-                Command::new(&heat)
+                    .arg(etc.join("msi/remove-duplicates.xsl"))
+                    .run(builder);
+            }
+            if built_tools.contains("clippy") {
+                command(&heat)
                     .current_dir(&exe)
                     .arg("dir")
-                    .arg("rust-std")
+                    .arg("clippy")
                     .args(heat_flags)
                     .arg("-cg")
-                    .arg("StdGroup")
+                    .arg("ClippyGroup")
                     .arg("-dr")
-                    .arg("Std")
+                    .arg("Clippy")
                     .arg("-var")
-                    .arg("var.StdDir")
+                    .arg("var.ClippyDir")
                     .arg("-out")
-                    .arg(exe.join("StdGroup.wxs")),
-            );
-            if built_tools.contains("rust-analyzer") {
-                builder.run(
-                    Command::new(&heat)
-                        .current_dir(&exe)
-                        .arg("dir")
-                        .arg("rust-analyzer")
-                        .args(heat_flags)
-                        .arg("-cg")
-                        .arg("RustAnalyzerGroup")
-                        .arg("-dr")
-                        .arg("RustAnalyzer")
-                        .arg("-var")
-                        .arg("var.RustAnalyzerDir")
-                        .arg("-out")
-                        .arg(exe.join("RustAnalyzerGroup.wxs"))
-                        .arg("-t")
-                        .arg(etc.join("msi/remove-duplicates.xsl")),
-                );
-            }
-            if built_tools.contains("clippy") {
-                builder.run(
-                    Command::new(&heat)
-                        .current_dir(&exe)
-                        .arg("dir")
-                        .arg("clippy")
-                        .args(heat_flags)
-                        .arg("-cg")
-                        .arg("ClippyGroup")
-                        .arg("-dr")
-                        .arg("Clippy")
-                        .arg("-var")
-                        .arg("var.ClippyDir")
-                        .arg("-out")
-                        .arg(exe.join("ClippyGroup.wxs"))
-                        .arg("-t")
-                        .arg(etc.join("msi/remove-duplicates.xsl")),
-                );
+                    .arg(exe.join("ClippyGroup.wxs"))
+                    .arg("-t")
+                    .arg(etc.join("msi/remove-duplicates.xsl"))
+                    .run(builder);
             }
             if built_tools.contains("miri") {
-                builder.run(
-                    Command::new(&heat)
-                        .current_dir(&exe)
-                        .arg("dir")
-                        .arg("miri")
-                        .args(heat_flags)
-                        .arg("-cg")
-                        .arg("MiriGroup")
-                        .arg("-dr")
-                        .arg("Miri")
-                        .arg("-var")
-                        .arg("var.MiriDir")
-                        .arg("-out")
-                        .arg(exe.join("MiriGroup.wxs"))
-                        .arg("-t")
-                        .arg(etc.join("msi/remove-duplicates.xsl")),
-                );
-            }
-            builder.run(
-                Command::new(&heat)
+                command(&heat)
                     .current_dir(&exe)
                     .arg("dir")
-                    .arg("rust-analysis")
+                    .arg("miri")
                     .args(heat_flags)
                     .arg("-cg")
-                    .arg("AnalysisGroup")
+                    .arg("MiriGroup")
                     .arg("-dr")
-                    .arg("Analysis")
+                    .arg("Miri")
                     .arg("-var")
-                    .arg("var.AnalysisDir")
+                    .arg("var.MiriDir")
                     .arg("-out")
-                    .arg(exe.join("AnalysisGroup.wxs"))
+                    .arg(exe.join("MiriGroup.wxs"))
                     .arg("-t")
-                    .arg(etc.join("msi/remove-duplicates.xsl")),
-            );
+                    .arg(etc.join("msi/remove-duplicates.xsl"))
+                    .run(builder);
+            }
+            command(&heat)
+                .current_dir(&exe)
+                .arg("dir")
+                .arg("rust-analysis")
+                .args(heat_flags)
+                .arg("-cg")
+                .arg("AnalysisGroup")
+                .arg("-dr")
+                .arg("Analysis")
+                .arg("-var")
+                .arg("var.AnalysisDir")
+                .arg("-out")
+                .arg(exe.join("AnalysisGroup.wxs"))
+                .arg("-t")
+                .arg(etc.join("msi/remove-duplicates.xsl"))
+                .run(builder);
             if target.ends_with("windows-gnu") {
-                builder.run(
-                    Command::new(&heat)
-                        .current_dir(&exe)
-                        .arg("dir")
-                        .arg("rust-mingw")
-                        .args(heat_flags)
-                        .arg("-cg")
-                        .arg("GccGroup")
-                        .arg("-dr")
-                        .arg("Gcc")
-                        .arg("-var")
-                        .arg("var.GccDir")
-                        .arg("-out")
-                        .arg(exe.join("GccGroup.wxs")),
-                );
+                command(&heat)
+                    .current_dir(&exe)
+                    .arg("dir")
+                    .arg("rust-mingw")
+                    .args(heat_flags)
+                    .arg("-cg")
+                    .arg("GccGroup")
+                    .arg("-dr")
+                    .arg("Gcc")
+                    .arg("-var")
+                    .arg("var.GccDir")
+                    .arg("-out")
+                    .arg(exe.join("GccGroup.wxs"))
+                    .run(builder);
             }
 
             let candle = |input: &Path| {
                 let output = exe.join(input.file_stem().unwrap()).with_extension("wixobj");
                 let arch = if target.contains("x86_64") { "x64" } else { "x86" };
-                let mut cmd = Command::new(&candle);
+                let mut cmd = command(&candle);
                 cmd.current_dir(&exe)
                     .arg("-nologo")
                     .arg("-dRustcDir=rustc")
@@ -1889,7 +1884,7 @@ impl Step for Extended {
                 if target.ends_with("windows-gnu") {
                     cmd.arg("-dGccDir=rust-mingw");
                 }
-                builder.run(&mut cmd);
+                cmd.run(builder);
             };
             candle(&xform(&etc.join("msi/rust.wxs")));
             candle(&etc.join("msi/ui.wxs"));
@@ -1921,7 +1916,7 @@ impl Step for Extended {
 
             builder.info(&format!("building `msi` installer with {light:?}"));
             let filename = format!("{}-{}.msi", pkgname(builder, "rust"), target.triple);
-            let mut cmd = Command::new(&light);
+            let mut cmd = command(&light);
             cmd.arg("-nologo")
                 .arg("-ext")
                 .arg("WixUIExtension")
@@ -1958,7 +1953,7 @@ impl Step for Extended {
             cmd.arg("-sice:ICE57");
 
             let _time = timeit(builder);
-            builder.run(&mut cmd);
+            cmd.run(builder);
 
             if !builder.config.dry_run() {
                 t!(move_file(exe.join(&filename), distdir(builder).join(&filename)));
@@ -1967,7 +1962,7 @@ impl Step for Extended {
     }
 }
 
-fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: TargetSelection) {
+fn add_env(builder: &Builder<'_>, cmd: &mut BootstrapCommand, target: TargetSelection) {
     let mut parts = builder.version.split('.');
     cmd.env("CFG_RELEASE_INFO", builder.rust_version())
         .env("CFG_RELEASE_NUM", &builder.version)
@@ -2074,10 +2069,14 @@ fn maybe_install_llvm(
     } else if let llvm::LlvmBuildStatus::AlreadyBuilt(llvm::LlvmResult { llvm_config, .. }) =
         llvm::prebuilt_llvm_config(builder, target)
     {
-        let mut cmd = Command::new(llvm_config);
+        let mut cmd = command(llvm_config);
         cmd.arg("--libfiles");
         builder.verbose(|| println!("running {cmd:?}"));
-        let files = if builder.config.dry_run() { "".into() } else { output(&mut cmd) };
+        let files = if builder.config.dry_run() {
+            "".into()
+        } else {
+            cmd.capture_stdout().run(builder).stdout()
+        };
         let build_llvm_out = &builder.llvm_out(builder.config.build);
         let target_llvm_out = &builder.llvm_out(target);
         for file in files.trim_end().split(' ') {
@@ -2225,6 +2224,11 @@ impl Step for LlvmBitcodeLinker {
 /// Tarball intended for internal consumption to ease rustc/std development.
 ///
 /// Should not be considered stable by end users.
+///
+/// In practice, this is the tarball that gets downloaded and used by
+/// `llvm.download-ci-llvm`.
+///
+/// (Don't confuse this with [`RustcDev`], with a `c`!)
 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
 pub struct RustDev {
     pub target: TargetSelection,
@@ -2261,9 +2265,6 @@ impl Step for RustDev {
 
         builder.ensure(crate::core::build_steps::llvm::Llvm { target });
 
-        // We want to package `lld` to use it with `download-ci-llvm`.
-        builder.ensure(crate::core::build_steps::llvm::Lld { target });
-
         let src_bindir = builder.llvm_out(target).join("bin");
         // If updating this, you likely want to change
         // src/bootstrap/download-ci-llvm-stamp as well, otherwise local users
@@ -2280,10 +2281,15 @@ impl Step for RustDev {
             }
         }
 
-        // We don't build LLD on some platforms, so only add it if it exists
-        let lld_path = builder.lld_out(target).join("bin").join(exe("lld", target));
-        if lld_path.exists() {
-            tarball.add_file(lld_path, "bin", 0o755);
+        if builder.config.lld_enabled {
+            // We want to package `lld` to use it with `download-ci-llvm`.
+            let lld_out = builder.ensure(crate::core::build_steps::llvm::Lld { target });
+
+            // We don't build LLD on some platforms, so only add it if it exists
+            let lld_path = lld_out.join("bin").join(exe("lld", target));
+            if lld_path.exists() {
+                tarball.add_file(lld_path, "bin", 0o755);
+            }
         }
 
         tarball.add_file(builder.llvm_filecheck(target), "bin", 0o755);
diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs
index 6748625f132..4b35d6c5d4c 100644
--- a/src/bootstrap/src/core/build_steps/doc.rs
+++ b/src/bootstrap/src/core/build_steps/doc.rs
@@ -154,7 +154,7 @@ impl<P: Step> Step for RustbookSrc<P> {
             builder.info(&format!("Rustbook ({target}) - {name}"));
             let _ = fs::remove_dir_all(&out);
 
-            builder.run(rustbook_cmd.arg("build").arg(&src).arg("-d").arg(&out));
+            rustbook_cmd.arg("build").arg(&src).arg("-d").arg(&out).run(builder);
 
             for lang in &self.languages {
                 let out = out.join(lang);
@@ -162,10 +162,15 @@ impl<P: Step> Step for RustbookSrc<P> {
                 builder.info(&format!("Rustbook ({target}) - {name} - {lang}"));
                 let _ = fs::remove_dir_all(&out);
 
-                let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook);
-                builder.run(
-                    rustbook_cmd.arg("build").arg(&src).arg("-d").arg(&out).arg("-l").arg(lang),
-                );
+                builder
+                    .tool_cmd(Tool::Rustbook)
+                    .arg("build")
+                    .arg(&src)
+                    .arg("-d")
+                    .arg(&out)
+                    .arg("-l")
+                    .arg(lang)
+                    .run(builder);
             }
         }
 
@@ -249,6 +254,7 @@ impl Step for TheBook {
         let shared_assets = builder.ensure(SharedAssets { target });
 
         // build the command first so we don't nest GHA groups
+        // FIXME: this doesn't do anything!
         builder.rustdoc_cmd(compiler);
 
         // build the redirect pages
@@ -300,7 +306,7 @@ fn invoke_rustdoc(
         cmd.arg("-Z").arg("unstable-options").arg("--disable-minification");
     }
 
-    builder.run(&mut cmd);
+    cmd.run(builder);
 }
 
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
@@ -394,7 +400,7 @@ impl Step for Standalone {
             } else {
                 cmd.arg("--markdown-css").arg("rust.css");
             }
-            builder.run(&mut cmd);
+            cmd.run(builder);
         }
 
         // We open doc/index.html as the default if invoked as `x.py doc --open`
@@ -493,7 +499,7 @@ impl Step for Releases {
                 cmd.arg("--disable-minification");
             }
 
-            builder.run(&mut cmd);
+            cmd.run(builder);
         }
 
         // We open doc/RELEASES.html as the default if invoked as `x.py doc --open RELEASES.md`
@@ -737,7 +743,7 @@ fn doc_std(
         format!("library{} in {} format", crate_description(requested_crates), format.as_str());
     let _guard = builder.msg_doc(compiler, description, target);
 
-    builder.run(&mut cargo.into());
+    cargo.into_cmd().run(builder);
     builder.cp_link_r(&out_dir, out);
 }
 
@@ -862,7 +868,7 @@ impl Step for Rustc {
         let proc_macro_out_dir = builder.stage_out(compiler, Mode::Rustc).join("doc");
         symlink_dir_force(&builder.config, &out, &proc_macro_out_dir);
 
-        builder.run(&mut cargo.into());
+        cargo.into_cmd().run(builder);
 
         if !builder.config.dry_run() {
             // Sanity check on linked compiler crates
@@ -888,12 +894,11 @@ impl Step for Rustc {
 macro_rules! tool_doc {
     (
         $tool: ident,
-        $should_run: literal,
         $path: literal,
         $(rustc_tool = $rustc_tool:literal, )?
-        $(in_tree = $in_tree:literal ,)?
         $(is_library = $is_library:expr,)?
         $(crates = $crates:expr)?
+        $(, submodule $(= $submodule:literal)? )?
        ) => {
         #[derive(Debug, Clone, Hash, PartialEq, Eq)]
         pub struct $tool {
@@ -907,7 +912,7 @@ macro_rules! tool_doc {
 
             fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
                 let builder = run.builder;
-                run.crate_or_deps($should_run).default_condition(builder.config.compiler_docs)
+                run.path($path).default_condition(builder.config.compiler_docs)
             }
 
             fn make_run(run: RunConfig<'_>) {
@@ -921,6 +926,15 @@ macro_rules! tool_doc {
             /// we do not merge it with the other documentation from std, test and
             /// proc_macros. This is largely just a wrapper around `cargo doc`.
             fn run(self, builder: &Builder<'_>) {
+                let source_type = SourceType::InTree;
+                $(
+                    let _ = source_type; // silence the "unused variable" warning
+                    let source_type = SourceType::Submodule;
+
+                    let path = Path::new(submodule_helper!( $path, submodule $( = $submodule )? ));
+                    builder.update_submodule(&path);
+                )?
+
                 let stage = builder.top_stage;
                 let target = self.target;
 
@@ -941,12 +955,6 @@ macro_rules! tool_doc {
                     builder.ensure(compile::Rustc::new(compiler, target));
                 }
 
-                let source_type = if true $(&& $in_tree)? {
-                    SourceType::InTree
-                } else {
-                    SourceType::Submodule
-                };
-
                 // Build cargo command.
                 let mut cargo = prepare_tool_cargo(
                     builder,
@@ -993,7 +1001,7 @@ macro_rules! tool_doc {
                 symlink_dir_force(&builder.config, &out, &proc_macro_out_dir);
 
                 let _guard = builder.msg_doc(compiler, stringify!($tool).to_lowercase(), target);
-                builder.run(&mut cargo.into());
+                cargo.into_cmd().run(builder);
 
                 if !builder.config.dry_run() {
                     // Sanity check on linked doc directories
@@ -1008,21 +1016,14 @@ macro_rules! tool_doc {
     }
 }
 
-tool_doc!(Rustdoc, "rustdoc-tool", "src/tools/rustdoc", crates = ["rustdoc", "rustdoc-json-types"]);
-tool_doc!(
-    Rustfmt,
-    "rustfmt-nightly",
-    "src/tools/rustfmt",
-    crates = ["rustfmt-nightly", "rustfmt-config_proc_macro"]
-);
-tool_doc!(Clippy, "clippy", "src/tools/clippy", crates = ["clippy_config", "clippy_utils"]);
-tool_doc!(Miri, "miri", "src/tools/miri", crates = ["miri"]);
+tool_doc!(Rustdoc, "src/tools/rustdoc", crates = ["rustdoc", "rustdoc-json-types"]);
+tool_doc!(Rustfmt, "src/tools/rustfmt", crates = ["rustfmt-nightly", "rustfmt-config_proc_macro"]);
+tool_doc!(Clippy, "src/tools/clippy", crates = ["clippy_config", "clippy_utils"]);
+tool_doc!(Miri, "src/tools/miri", crates = ["miri"]);
 tool_doc!(
     Cargo,
-    "cargo",
     "src/tools/cargo",
     rustc_tool = false,
-    in_tree = false,
     crates = [
         "cargo",
         "cargo-credential",
@@ -1034,12 +1035,12 @@ tool_doc!(
         "crates-io",
         "mdman",
         "rustfix",
-    ]
+    ],
+    submodule = "src/tools/cargo"
 );
-tool_doc!(Tidy, "tidy", "src/tools/tidy", rustc_tool = false, crates = ["tidy"]);
+tool_doc!(Tidy, "src/tools/tidy", rustc_tool = false, crates = ["tidy"]);
 tool_doc!(
     Bootstrap,
-    "bootstrap",
     "src/bootstrap",
     rustc_tool = false,
     is_library = true,
@@ -1047,7 +1048,6 @@ tool_doc!(
 );
 tool_doc!(
     RunMakeSupport,
-    "run_make_support",
     "src/tools/run-make-support",
     rustc_tool = false,
     is_library = true,
@@ -1080,12 +1080,7 @@ impl Step for ErrorIndex {
         builder.info(&format!("Documenting error index ({})", self.target));
         let out = builder.doc_out(self.target);
         t!(fs::create_dir_all(&out));
-        let mut index = tool::ErrorIndex::command(builder);
-        index.arg("html");
-        index.arg(out);
-        index.arg(&builder.version);
-
-        builder.run(&mut index);
+        tool::ErrorIndex::command(builder).arg("html").arg(out).arg(&builder.version).run(builder);
     }
 }
 
@@ -1121,7 +1116,7 @@ impl Step for UnstableBookGen {
         cmd.arg(builder.src.join("src"));
         cmd.arg(out);
 
-        builder.run(&mut cmd);
+        cmd.run(builder);
     }
 }
 
@@ -1216,7 +1211,7 @@ impl Step for RustcBook {
             self.compiler.host,
             self.target,
         );
-        builder.run(&mut cmd);
+        cmd.run(builder);
         drop(doc_generator_guard);
 
         // Run rustbook/mdbook to generate the HTML pages.
diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs
index f5e34672686..d3ac2bae1e8 100644
--- a/src/bootstrap/src/core/build_steps/format.rs
+++ b/src/bootstrap/src/core/build_steps/format.rs
@@ -1,13 +1,14 @@
 //! Runs rustfmt on the repository.
 
 use crate::core::builder::Builder;
-use crate::utils::helpers::{self, output, program_out_of_date, t};
+use crate::utils::exec::command;
+use crate::utils::helpers::{self, program_out_of_date, t};
 use build_helper::ci::CiEnv;
 use build_helper::git::get_git_modified_files;
 use ignore::WalkBuilder;
 use std::collections::VecDeque;
 use std::path::{Path, PathBuf};
-use std::process::{Command, Stdio};
+use std::process::Command;
 use std::sync::mpsc::SyncSender;
 use std::sync::Mutex;
 
@@ -53,19 +54,17 @@ fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl F
 fn get_rustfmt_version(build: &Builder<'_>) -> Option<(String, PathBuf)> {
     let stamp_file = build.out.join("rustfmt.stamp");
 
-    let mut cmd = Command::new(match build.initial_rustfmt() {
+    let mut cmd = command(match build.initial_rustfmt() {
         Some(p) => p,
         None => return None,
     });
     cmd.arg("--version");
-    let output = match cmd.output() {
-        Ok(status) => status,
-        Err(_) => return None,
-    };
-    if !output.status.success() {
+
+    let output = cmd.capture().allow_failure().run(build);
+    if output.is_failure() {
         return None;
     }
-    Some((String::from_utf8(output.stdout).unwrap(), stamp_file))
+    Some((output.stdout(), stamp_file))
 }
 
 /// Return whether the format cache can be reused.
@@ -160,36 +159,27 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) {
             override_builder.add(&format!("!{ignore}")).expect(&ignore);
         }
     }
-    let git_available = match helpers::git(None)
-        .arg("--version")
-        .stdout(Stdio::null())
-        .stderr(Stdio::null())
-        .status()
-    {
-        Ok(status) => status.success(),
-        Err(_) => false,
-    };
+    let git_available =
+        helpers::git(None).capture().allow_failure().arg("--version").run(build).is_success();
 
     let mut adjective = None;
     if git_available {
-        let in_working_tree = match helpers::git(Some(&build.src))
+        let in_working_tree = helpers::git(Some(&build.src))
+            .capture()
+            .allow_failure()
             .arg("rev-parse")
             .arg("--is-inside-work-tree")
-            .stdout(Stdio::null())
-            .stderr(Stdio::null())
-            .status()
-        {
-            Ok(status) => status.success(),
-            Err(_) => false,
-        };
+            .run(build)
+            .is_success();
         if in_working_tree {
-            let untracked_paths_output = output(
-                helpers::git(Some(&build.src))
-                    .arg("status")
-                    .arg("--porcelain")
-                    .arg("-z")
-                    .arg("--untracked-files=normal"),
-            );
+            let untracked_paths_output = helpers::git(Some(&build.src))
+                .capture_stdout()
+                .arg("status")
+                .arg("--porcelain")
+                .arg("-z")
+                .arg("--untracked-files=normal")
+                .run(build)
+                .stdout();
             let untracked_paths: Vec<_> = untracked_paths_output
                 .split_terminator('\0')
                 .filter_map(
diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs
index c47233ca42a..d3e9d6d7875 100644
--- a/src/bootstrap/src/core/build_steps/install.rs
+++ b/src/bootstrap/src/core/build_steps/install.rs
@@ -6,11 +6,11 @@
 use std::env;
 use std::fs;
 use std::path::{Component, Path, PathBuf};
-use std::process::Command;
 
 use crate::core::build_steps::dist;
 use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
 use crate::core::config::{Config, TargetSelection};
+use crate::utils::exec::command;
 use crate::utils::helpers::t;
 use crate::utils::tarball::GeneratedTarball;
 use crate::{Compiler, Kind};
@@ -102,7 +102,7 @@ fn install_sh(
     let empty_dir = builder.out.join("tmp/empty_dir");
     t!(fs::create_dir_all(&empty_dir));
 
-    let mut cmd = Command::new(SHELL);
+    let mut cmd = command(SHELL);
     cmd.current_dir(&empty_dir)
         .arg(sanitize_sh(&tarball.decompressed_output().join("install.sh")))
         .arg(format!("--prefix={}", prepare_dir(&destdir_env, prefix)))
@@ -113,7 +113,7 @@ fn install_sh(
         .arg(format!("--libdir={}", prepare_dir(&destdir_env, libdir)))
         .arg(format!("--mandir={}", prepare_dir(&destdir_env, mandir)))
         .arg("--disable-ldconfig");
-    builder.run(&mut cmd);
+    cmd.run(builder);
     t!(fs::remove_dir_all(&empty_dir));
 }
 
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index f90403d2ec4..872823506f8 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -14,7 +14,6 @@ use std::ffi::{OsStr, OsString};
 use std::fs::{self, File};
 use std::io;
 use std::path::{Path, PathBuf};
-use std::process::Command;
 use std::sync::OnceLock;
 
 use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
@@ -25,6 +24,7 @@ use crate::utils::helpers::{
 };
 use crate::{generate_smart_stamp_hash, CLang, GitRepo, Kind};
 
+use crate::utils::exec::command;
 use build_helper::ci::CiEnv;
 use build_helper::git::get_git_merge_base;
 
@@ -172,7 +172,7 @@ pub(crate) fn detect_llvm_sha(config: &Config, is_git: bool) -> String {
             // the LLVM shared object file is named `LLVM-12-rust-{version}-nightly`
             config.src.join("src/version"),
         ]);
-        output(&mut rev_list).trim().to_owned()
+        output(&mut rev_list.command).trim().to_owned()
     } else if let Some(info) = channel::read_commit_info_file(&config.src) {
         info.sha.trim().to_owned()
     } else {
@@ -217,6 +217,7 @@ pub(crate) fn is_ci_llvm_available(config: &Config, asserts: bool) -> bool {
         ("arm-unknown-linux-gnueabihf", false),
         ("armv7-unknown-linux-gnueabihf", false),
         ("loongarch64-unknown-linux-gnu", false),
+        ("loongarch64-unknown-linux-musl", false),
         ("mips-unknown-linux-gnu", false),
         ("mips64-unknown-linux-gnuabi64", false),
         ("mips64el-unknown-linux-gnuabi64", false),
@@ -252,7 +253,8 @@ pub(crate) fn is_ci_llvm_modified(config: &Config) -> bool {
         // We assume we have access to git, so it's okay to unconditionally pass
         // `true` here.
         let llvm_sha = detect_llvm_sha(config, true);
-        let head_sha = output(helpers::git(Some(&config.src)).arg("rev-parse").arg("HEAD"));
+        let head_sha =
+            output(&mut helpers::git(Some(&config.src)).arg("rev-parse").arg("HEAD").command);
         let head_sha = head_sha.trim();
         llvm_sha == head_sha
     }
@@ -406,18 +408,21 @@ impl Step for Llvm {
             cfg.define("LLVM_LINK_LLVM_DYLIB", "ON");
         }
 
-        if (target.starts_with("riscv") || target.starts_with("csky"))
+        if (target.starts_with("csky")
+            || target.starts_with("riscv")
+            || target.starts_with("sparc-"))
             && !target.contains("freebsd")
             && !target.contains("openbsd")
             && !target.contains("netbsd")
         {
-            // RISC-V and CSKY GCC erroneously requires linking against
+            // CSKY and RISC-V GCC erroneously requires linking against
             // `libatomic` when using 1-byte and 2-byte C++
             // atomics but the LLVM build system check cannot
             // detect this. Therefore it is set manually here.
             // Some BSD uses Clang as its system compiler and
             // provides no libatomic in its base system so does
-            // not want this.
+            // not want this. 32-bit SPARC requires linking against
+            // libatomic as well.
             ldflags.exe.push(" -latomic");
             ldflags.shared.push(" -latomic");
         }
@@ -473,7 +478,8 @@ impl Step for Llvm {
             let LlvmResult { llvm_config, .. } =
                 builder.ensure(Llvm { target: builder.config.build });
             if !builder.config.dry_run() {
-                let llvm_bindir = output(Command::new(&llvm_config).arg("--bindir"));
+                let llvm_bindir =
+                    command(&llvm_config).capture_stdout().arg("--bindir").run(builder).stdout();
                 let host_bin = Path::new(llvm_bindir.trim());
                 cfg.define(
                     "LLVM_TABLEGEN",
@@ -523,8 +529,8 @@ impl Step for Llvm {
 
         // Helper to find the name of LLVM's shared library on darwin and linux.
         let find_llvm_lib_name = |extension| {
-            let mut cmd = Command::new(&res.llvm_config);
-            let version = output(cmd.arg("--version"));
+            let version =
+                command(&res.llvm_config).capture_stdout().arg("--version").run(builder).stdout();
             let major = version.split('.').next().unwrap();
 
             match &llvm_version_suffix {
@@ -580,8 +586,7 @@ fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) {
         return;
     }
 
-    let mut cmd = Command::new(llvm_config);
-    let version = output(cmd.arg("--version"));
+    let version = command(llvm_config).capture_stdout().arg("--version").run(builder).stdout();
     let mut parts = version.split('.').take(2).filter_map(|s| s.parse::<u32>().ok());
     if let (Some(major), Some(_minor)) = (parts.next(), parts.next()) {
         if major >= 17 {
@@ -748,7 +753,7 @@ fn configure_cmake(
     }
 
     if builder.config.llvm_clang_cl.is_some() {
-        cflags.push(&format!(" --target={target}"));
+        cflags.push(format!(" --target={target}"));
     }
     cfg.define("CMAKE_C_FLAGS", cflags);
     let mut cxxflags: OsString = builder
@@ -767,7 +772,7 @@ fn configure_cmake(
         cxxflags.push(s);
     }
     if builder.config.llvm_clang_cl.is_some() {
-        cxxflags.push(&format!(" --target={target}"));
+        cxxflags.push(format!(" --target={target}"));
     }
     cfg.define("CMAKE_CXX_FLAGS", cxxflags);
     if let Some(ar) = builder.ar(target) {
@@ -908,7 +913,7 @@ impl Step for Lld {
                 // Find clang's runtime library directory and push that as a search path to the
                 // cmake linker flags.
                 let clang_rt_dir = get_clang_cl_resource_dir(clang_cl_path);
-                ldflags.push_all(&format!("/libpath:{}", clang_rt_dir.display()));
+                ldflags.push_all(format!("/libpath:{}", clang_rt_dir.display()));
             }
         }
 
diff --git a/src/bootstrap/src/core/build_steps/mod.rs b/src/bootstrap/src/core/build_steps/mod.rs
index 381ee7ef53b..004174e35e1 100644
--- a/src/bootstrap/src/core/build_steps/mod.rs
+++ b/src/bootstrap/src/core/build_steps/mod.rs
@@ -7,6 +7,7 @@ pub(crate) mod doc;
 pub(crate) mod format;
 pub(crate) mod install;
 pub(crate) mod llvm;
+pub(crate) mod perf;
 pub(crate) mod run;
 pub(crate) mod setup;
 pub(crate) mod suggest;
diff --git a/src/bootstrap/src/core/build_steps/perf.rs b/src/bootstrap/src/core/build_steps/perf.rs
new file mode 100644
index 00000000000..5b83080a326
--- /dev/null
+++ b/src/bootstrap/src/core/build_steps/perf.rs
@@ -0,0 +1,35 @@
+use crate::core::build_steps::compile::{Std, Sysroot};
+use crate::core::build_steps::tool::{RustcPerf, Tool};
+use crate::core::builder::Builder;
+use crate::core::config::DebuginfoLevel;
+
+/// Performs profiling using `rustc-perf` on a built version of the compiler.
+pub fn perf(builder: &Builder<'_>) {
+    let collector = builder.ensure(RustcPerf {
+        compiler: builder.compiler(0, builder.config.build),
+        target: builder.config.build,
+    });
+
+    if builder.build.config.rust_debuginfo_level_rustc == DebuginfoLevel::None {
+        builder.info(r#"WARNING: You are compiling rustc without debuginfo, this will make profiling less useful.
+Consider setting `rust.debuginfo-level = 1` in `config.toml`."#);
+    }
+
+    let compiler = builder.compiler(builder.top_stage, builder.config.build);
+    builder.ensure(Std::new(compiler, builder.config.build));
+    let sysroot = builder.ensure(Sysroot::new(compiler));
+    let rustc = sysroot.join("bin/rustc");
+
+    let rustc_perf_dir = builder.build.tempdir().join("rustc-perf");
+    let profile_results_dir = rustc_perf_dir.join("results");
+
+    // We need to take args passed after `--` and pass them to `rustc-perf-wrapper`
+    let args = std::env::args().skip_while(|a| a != "--").skip(1);
+
+    let mut cmd = builder.tool_cmd(Tool::RustcPerfWrapper);
+    cmd.env("RUSTC_REAL", rustc)
+        .env("PERF_COLLECTOR", collector)
+        .env("PERF_RESULT_DIR", profile_results_dir)
+        .args(args);
+    cmd.run(builder);
+}
diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs
index 9268b335db7..3a2d3f67522 100644
--- a/src/bootstrap/src/core/build_steps/run.rs
+++ b/src/bootstrap/src/core/build_steps/run.rs
@@ -4,7 +4,6 @@
 //! If it can be reached from `./x.py run` it can go here.
 
 use std::path::PathBuf;
-use std::process::Command;
 
 use crate::core::build_steps::dist::distdir;
 use crate::core::build_steps::test;
@@ -12,7 +11,7 @@ use crate::core::build_steps::tool::{self, SourceType, Tool};
 use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
 use crate::core::config::flags::get_completion;
 use crate::core::config::TargetSelection;
-use crate::utils::helpers::output;
+use crate::utils::exec::command;
 use crate::Mode;
 
 #[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
@@ -41,7 +40,7 @@ impl Step for BuildManifest {
             panic!("\n\nfailed to specify `dist.upload-addr` in `config.toml`\n\n")
         });
 
-        let today = output(Command::new("date").arg("+%Y-%m-%d"));
+        let today = command("date").capture_stdout().arg("+%Y-%m-%d").run(builder).stdout();
 
         cmd.arg(sign);
         cmd.arg(distdir(builder));
@@ -50,7 +49,7 @@ impl Step for BuildManifest {
         cmd.arg(&builder.config.channel);
 
         builder.create_dir(&distdir(builder));
-        builder.run(&mut cmd);
+        cmd.run(builder);
     }
 }
 
@@ -72,7 +71,7 @@ impl Step for BumpStage0 {
     fn run(self, builder: &Builder<'_>) -> Self::Output {
         let mut cmd = builder.tool_cmd(Tool::BumpStage0);
         cmd.args(builder.config.args());
-        builder.run(&mut cmd);
+        cmd.run(builder);
     }
 }
 
@@ -94,7 +93,7 @@ impl Step for ReplaceVersionPlaceholder {
     fn run(self, builder: &Builder<'_>) -> Self::Output {
         let mut cmd = builder.tool_cmd(Tool::ReplaceVersionPlaceholder);
         cmd.arg(&builder.src);
-        builder.run(&mut cmd);
+        cmd.run(builder);
     }
 }
 
@@ -158,8 +157,7 @@ impl Step for Miri {
         // after another --, so this must be at the end.
         miri.args(builder.config.args());
 
-        let mut miri = Command::from(miri);
-        builder.run(&mut miri);
+        miri.into_cmd().run(builder);
     }
 }
 
@@ -189,7 +187,7 @@ impl Step for CollectLicenseMetadata {
         let mut cmd = builder.tool_cmd(Tool::CollectLicenseMetadata);
         cmd.env("REUSE_EXE", reuse);
         cmd.env("DEST", &dest);
-        builder.run(&mut cmd);
+        cmd.run(builder);
 
         dest
     }
@@ -219,7 +217,7 @@ impl Step for GenerateCopyright {
         let mut cmd = builder.tool_cmd(Tool::GenerateCopyright);
         cmd.env("LICENSE_METADATA", &license_metadata);
         cmd.env("DEST", &dest);
-        builder.run(&mut cmd);
+        cmd.run(builder);
 
         dest
     }
@@ -243,7 +241,7 @@ impl Step for GenerateWindowsSys {
     fn run(self, builder: &Builder<'_>) {
         let mut cmd = builder.tool_cmd(Tool::GenerateWindowsSys);
         cmd.arg(&builder.src);
-        builder.run(&mut cmd);
+        cmd.run(builder);
     }
 }
 
diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs
index 947c74f32c9..e6a09e8cb8e 100644
--- a/src/bootstrap/src/core/build_steps/setup.rs
+++ b/src/bootstrap/src/core/build_steps/setup.rs
@@ -484,6 +484,7 @@ impl Step for Hook {
 fn install_git_hook_maybe(config: &Config) -> io::Result<()> {
     let git = helpers::git(Some(&config.src))
         .args(["rev-parse", "--git-common-dir"])
+        .command
         .output()
         .map(|output| {
             assert!(output.status.success(), "failed to run `git`");
diff --git a/src/bootstrap/src/core/build_steps/suggest.rs b/src/bootstrap/src/core/build_steps/suggest.rs
index 754d1e61da8..2d4409d27c6 100644
--- a/src/bootstrap/src/core/build_steps/suggest.rs
+++ b/src/bootstrap/src/core/build_steps/suggest.rs
@@ -14,22 +14,12 @@ pub fn suggest(builder: &Builder<'_>, run: bool) {
     let git_config = builder.config.git_config();
     let suggestions = builder
         .tool_cmd(Tool::SuggestTests)
+        .capture_stdout()
         .env("SUGGEST_TESTS_GIT_REPOSITORY", git_config.git_repository)
         .env("SUGGEST_TESTS_NIGHTLY_BRANCH", git_config.nightly_branch)
-        .output()
-        .expect("failed to run `suggest-tests` tool");
+        .run(builder)
+        .stdout();
 
-    if !suggestions.status.success() {
-        println!("failed to run `suggest-tests` tool ({})", suggestions.status);
-        println!(
-            "`suggest_tests` stdout:\n{}`suggest_tests` stderr:\n{}",
-            String::from_utf8(suggestions.stdout).unwrap(),
-            String::from_utf8(suggestions.stderr).unwrap()
-        );
-        panic!("failed to run `suggest-tests`");
-    }
-
-    let suggestions = String::from_utf8(suggestions.stdout).unwrap();
     let suggestions = suggestions
         .lines()
         .map(|line| {
diff --git a/src/bootstrap/src/core/build_steps/synthetic_targets.rs b/src/bootstrap/src/core/build_steps/synthetic_targets.rs
index 281a9b093b9..021680302cd 100644
--- a/src/bootstrap/src/core/build_steps/synthetic_targets.rs
+++ b/src/bootstrap/src/core/build_steps/synthetic_targets.rs
@@ -9,8 +9,8 @@
 
 use crate::core::builder::{Builder, ShouldRun, Step};
 use crate::core::config::TargetSelection;
+use crate::utils::exec::command;
 use crate::Compiler;
-use std::process::{Command, Stdio};
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub(crate) struct MirOptPanicAbortSyntheticTarget {
@@ -56,7 +56,7 @@ fn create_synthetic_target(
         return TargetSelection::create_synthetic(&name, path.to_str().unwrap());
     }
 
-    let mut cmd = Command::new(builder.rustc(compiler));
+    let mut cmd = command(builder.rustc(compiler));
     cmd.arg("--target").arg(base.rustc_target_arg());
     cmd.args(["-Zunstable-options", "--print", "target-spec-json"]);
 
@@ -64,14 +64,8 @@ fn create_synthetic_target(
     // we cannot use nightly features. So `RUSTC_BOOTSTRAP` is needed here.
     cmd.env("RUSTC_BOOTSTRAP", "1");
 
-    cmd.stdout(Stdio::piped());
-
-    let output = cmd.spawn().unwrap().wait_with_output().unwrap();
-    if !output.status.success() {
-        panic!("failed to gather the target spec for {base}");
-    }
-
-    let mut spec: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap();
+    let output = cmd.capture().run(builder).stdout();
+    let mut spec: serde_json::Value = serde_json::from_slice(output.as_bytes()).unwrap();
     let spec_map = spec.as_object_mut().unwrap();
 
     // The `is-builtin` attribute of a spec needs to be removed, otherwise rustc will complain.
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 445096e9786..0b60587bb79 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -26,11 +26,10 @@ use crate::core::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step};
 use crate::core::config::flags::get_completion;
 use crate::core::config::flags::Subcommand;
 use crate::core::config::TargetSelection;
-use crate::utils::exec::BootstrapCommand;
+use crate::utils::exec::{command, BootstrapCommand};
 use crate::utils::helpers::{
     self, add_link_lib_path, add_rustdoc_cargo_linker_args, dylib_path, dylib_path_var,
-    linker_args, linker_flags, output, t, target_supports_cranelift_backend, up_to_date,
-    LldThreads,
+    linker_args, linker_flags, t, target_supports_cranelift_backend, up_to_date, LldThreads,
 };
 use crate::utils::render_tests::{add_flags_and_try_run_tests, try_run_tests};
 use crate::{envify, CLang, DocTests, GitRepo, Mode};
@@ -150,13 +149,13 @@ You can skip linkcheck with --skip src/tools/linkchecker"
         builder.default_doc(&[]);
 
         // Build the linkchecker before calling `msg`, since GHA doesn't support nested groups.
-        let mut linkchecker = builder.tool_cmd(Tool::Linkchecker);
+        let linkchecker = builder.tool_cmd(Tool::Linkchecker);
 
         // Run the linkchecker.
         let _guard =
             builder.msg(Kind::Test, compiler.stage, "Linkcheck", bootstrap_host, bootstrap_host);
         let _time = helpers::timeit(builder);
-        builder.run_delaying_failure(linkchecker.arg(builder.out.join(host.triple).join("doc")));
+        linkchecker.delay_failure().arg(builder.out.join(host.triple).join("doc")).run(builder);
     }
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
@@ -201,7 +200,7 @@ impl Step for HtmlCheck {
         if !check_if_tidy_is_installed() {
             eprintln!("not running HTML-check tool because `tidy` is missing");
             eprintln!(
-                "Note that `tidy` is not the in-tree `src/tools/tidy` but needs to be installed"
+                "You need the HTML tidy tool https://www.html-tidy.org/, this tool is *not* part of the rust project and needs to be installed separately, for example via your package manager."
             );
             panic!("Cannot run html-check tests");
         }
@@ -213,9 +212,11 @@ impl Step for HtmlCheck {
             builder,
         ));
 
-        builder.run_delaying_failure(
-            builder.tool_cmd(Tool::HtmlChecker).arg(builder.doc_out(self.target)),
-        );
+        builder
+            .tool_cmd(Tool::HtmlChecker)
+            .delay_failure()
+            .arg(builder.doc_out(self.target))
+            .run(builder);
     }
 }
 
@@ -254,14 +255,13 @@ impl Step for Cargotest {
 
         let _time = helpers::timeit(builder);
         let mut cmd = builder.tool_cmd(Tool::CargoTest);
-        let cmd = cmd
-            .arg(&cargo)
+        cmd.arg(&cargo)
             .arg(&out_dir)
             .args(builder.config.test_args())
             .env("RUSTC", builder.rustc(compiler))
             .env("RUSTDOC", builder.rustdoc(compiler));
-        add_rustdoc_cargo_linker_args(cmd, builder, compiler.host, LldThreads::No);
-        builder.run_delaying_failure(cmd);
+        add_rustdoc_cargo_linker_args(&mut cmd, builder, compiler.host, LldThreads::No);
+        cmd.delay_failure().run(builder);
     }
 }
 
@@ -459,10 +459,10 @@ impl Miri {
         // Tell it where to put the sysroot.
         cargo.env("MIRI_SYSROOT", &miri_sysroot);
 
-        let mut cargo = Command::from(cargo);
+        let mut cargo = BootstrapCommand::from(cargo);
         let _guard =
             builder.msg(Kind::Build, compiler.stage, "miri sysroot", compiler.host, target);
-        builder.run(&mut cargo);
+        cargo.run(builder);
 
         // # Determine where Miri put its sysroot.
         // To this end, we run `cargo miri setup --print-sysroot` and capture the output.
@@ -471,17 +471,12 @@ impl Miri {
         // We re-use the `cargo` from above.
         cargo.arg("--print-sysroot");
 
-        // FIXME: Is there a way in which we can re-use the usual `run` helpers?
         if builder.config.dry_run() {
             String::new()
         } else {
             builder.verbose(|| println!("running: {cargo:?}"));
-            let out =
-                cargo.output().expect("We already ran `cargo miri setup` before and that worked");
-            assert!(out.status.success(), "`cargo miri setup` returned with non-0 exit code");
+            let stdout = cargo.capture_stdout().run(builder).stdout();
             // Output is "<sysroot>\n".
-            let stdout = String::from_utf8(out.stdout)
-                .expect("`cargo miri setup` stdout is not valid UTF-8");
             let sysroot = stdout.trim_end();
             builder.verbose(|| println!("`cargo miri setup --print-sysroot` said: {sysroot:?}"));
             sysroot.to_owned()
@@ -568,7 +563,7 @@ impl Step for Miri {
         {
             let _guard = builder.msg_sysroot_tool(Kind::Test, stage, "miri", host, target);
             let _time = helpers::timeit(builder);
-            builder.run(&mut cargo);
+            cargo.run(builder);
         }
 
         // Run it again for mir-opt-level 4 to catch some miscompilations.
@@ -590,7 +585,7 @@ impl Step for Miri {
                     target,
                 );
                 let _time = helpers::timeit(builder);
-                builder.run(&mut cargo);
+                cargo.run(builder);
             }
         }
     }
@@ -655,11 +650,11 @@ impl Step for CargoMiri {
 
         // Finally, pass test-args and run everything.
         cargo.arg("--").args(builder.config.test_args());
-        let mut cargo = Command::from(cargo);
+        let mut cargo = BootstrapCommand::from(cargo);
         {
             let _guard = builder.msg_sysroot_tool(Kind::Test, stage, "cargo-miri", host, target);
             let _time = helpers::timeit(builder);
-            builder.run(&mut cargo);
+            cargo.run(builder);
         }
     }
 }
@@ -755,12 +750,12 @@ impl Step for Clippy {
         cargo.env("HOST_LIBS", host_libs);
 
         cargo.add_rustc_lib_path(builder);
-        let mut cargo = prepare_cargo_test(cargo, &[], &[], "clippy", compiler, host, builder);
+        let cargo = prepare_cargo_test(cargo, &[], &[], "clippy", compiler, host, builder);
 
         let _guard = builder.msg_sysroot_tool(Kind::Test, compiler.stage, "clippy", host, host);
 
         // Clippy reports errors if it blessed the outputs
-        if builder.run_cmd(BootstrapCommand::from(&mut cargo).allow_failure()) {
+        if cargo.allow_failure().run(builder).is_success() {
             // The tests succeeded; nothing to do.
             return;
         }
@@ -813,7 +808,7 @@ impl Step for RustdocTheme {
             .env("RUSTC_BOOTSTRAP", "1");
         cmd.args(linker_args(builder, self.compiler.host, LldThreads::No));
 
-        builder.run_delaying_failure(&mut cmd);
+        cmd.delay_failure().run(builder);
     }
 }
 
@@ -839,7 +834,7 @@ impl Step for RustdocJSStd {
     fn run(self, builder: &Builder<'_>) {
         let nodejs =
             builder.config.nodejs.as_ref().expect("need nodejs to run rustdoc-js-std tests");
-        let mut command = Command::new(nodejs);
+        let mut command = command(nodejs);
         command
             .arg(builder.src.join("src/tools/rustdoc-js/tester.js"))
             .arg("--crate-name")
@@ -873,7 +868,7 @@ impl Step for RustdocJSStd {
             builder.config.build,
             self.target,
         );
-        builder.run(&mut command);
+        command.run(builder);
     }
 }
 
@@ -910,25 +905,26 @@ impl Step for RustdocJSNotStd {
     }
 }
 
-fn get_browser_ui_test_version_inner(npm: &Path, global: bool) -> Option<String> {
-    let mut command = Command::new(npm);
+fn get_browser_ui_test_version_inner(
+    builder: &Builder<'_>,
+    npm: &Path,
+    global: bool,
+) -> Option<String> {
+    let mut command = command(npm).capture();
     command.arg("list").arg("--parseable").arg("--long").arg("--depth=0");
     if global {
         command.arg("--global");
     }
-    let lines = command
-        .output()
-        .map(|output| String::from_utf8_lossy(&output.stdout).into_owned())
-        .unwrap_or_default();
+    let lines = command.allow_failure().run(builder).stdout();
     lines
         .lines()
         .find_map(|l| l.split(':').nth(1)?.strip_prefix("browser-ui-test@"))
         .map(|v| v.to_owned())
 }
 
-fn get_browser_ui_test_version(npm: &Path) -> Option<String> {
-    get_browser_ui_test_version_inner(npm, false)
-        .or_else(|| get_browser_ui_test_version_inner(npm, true))
+fn get_browser_ui_test_version(builder: &Builder<'_>, npm: &Path) -> Option<String> {
+    get_browser_ui_test_version_inner(builder, npm, false)
+        .or_else(|| get_browser_ui_test_version_inner(builder, npm, true))
 }
 
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
@@ -952,7 +948,7 @@ impl Step for RustdocGUI {
                     .config
                     .npm
                     .as_ref()
-                    .map(|p| get_browser_ui_test_version(p).is_some())
+                    .map(|p| get_browser_ui_test_version(builder, p).is_some())
                     .unwrap_or(false)
         }))
     }
@@ -1042,8 +1038,6 @@ impl Step for Tidy {
     /// Once tidy passes, this step also runs `fmt --check` if tests are being run
     /// for the `dev` or `nightly` channels.
     fn run(self, builder: &Builder<'_>) {
-        builder.build.update_submodule(Path::new("src/tools/rustc-perf"));
-
         let mut cmd = builder.tool_cmd(Tool::Tidy);
         cmd.arg(&builder.src);
         cmd.arg(&builder.initial_cargo);
@@ -1093,7 +1087,7 @@ HELP: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to
         }
 
         builder.info("tidy check");
-        builder.run_delaying_failure(&mut cmd);
+        cmd.delay_failure().run(builder);
 
         builder.info("x.py completions check");
         let [bash, zsh, fish, powershell] = ["x.py.sh", "x.py.zsh", "x.py.fish", "x.py.ps1"]
@@ -1300,8 +1294,7 @@ impl Step for RunMakeSupport {
             &[],
         );
 
-        let mut cargo = Command::from(cargo);
-        builder.run(&mut cargo);
+        cargo.into_cmd().run(builder);
 
         let lib_name = "librun_make_support.rlib";
         let lib = builder.tools_dir(self.compiler).join(lib_name);
@@ -1812,25 +1805,23 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
             cmd.arg("--gdb").arg(gdb);
         }
 
-        let run = |cmd: &mut Command| {
-            cmd.output().map(|output| {
-                String::from_utf8_lossy(&output.stdout)
-                    .lines()
-                    .next()
-                    .unwrap_or_else(|| panic!("{:?} failed {:?}", cmd, output))
-                    .to_string()
-            })
-        };
-
         let lldb_exe = builder.config.lldb.clone().unwrap_or_else(|| PathBuf::from("lldb"));
-        let lldb_version = Command::new(&lldb_exe)
+        let lldb_version = command(&lldb_exe)
+            .capture()
+            .allow_failure()
             .arg("--version")
-            .output()
-            .map(|output| String::from_utf8_lossy(&output.stdout).to_string())
-            .ok();
+            .run(builder)
+            .stdout_if_ok()
+            .and_then(|v| if v.trim().is_empty() { None } else { Some(v) });
         if let Some(ref vers) = lldb_version {
             cmd.arg("--lldb-version").arg(vers);
-            let lldb_python_dir = run(Command::new(&lldb_exe).arg("-P")).ok();
+            let lldb_python_dir = command(&lldb_exe)
+                .allow_failure()
+                .capture_stdout()
+                .arg("-P")
+                .run(builder)
+                .stdout_if_ok()
+                .map(|p| p.lines().next().expect("lldb Python dir not found").to_string());
             if let Some(ref dir) = lldb_python_dir {
                 cmd.arg("--lldb-python-dir").arg(dir);
             }
@@ -1886,8 +1877,11 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
             let llvm::LlvmResult { llvm_config, .. } =
                 builder.ensure(llvm::Llvm { target: builder.config.build });
             if !builder.config.dry_run() {
-                let llvm_version = output(Command::new(&llvm_config).arg("--version"));
-                let llvm_components = output(Command::new(&llvm_config).arg("--components"));
+                let llvm_version =
+                    builder.run(command(&llvm_config).capture_stdout().arg("--version")).stdout();
+                let llvm_components = builder
+                    .run(command(&llvm_config).capture_stdout().arg("--components"))
+                    .stdout();
                 // Remove trailing newline from llvm-config output.
                 cmd.arg("--llvm-version")
                     .arg(llvm_version.trim())
@@ -1906,7 +1900,8 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
             // separate compilations. We can add LLVM's library path to the
             // platform-specific environment variable as a workaround.
             if !builder.config.dry_run() && suite.ends_with("fulldeps") {
-                let llvm_libdir = output(Command::new(&llvm_config).arg("--libdir"));
+                let llvm_libdir =
+                    builder.run(command(&llvm_config).capture_stdout().arg("--libdir")).stdout();
                 add_link_lib_path(vec![llvm_libdir.trim().into()], &mut cmd);
             }
 
@@ -2062,7 +2057,8 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
         cmd.arg("--git-repository").arg(git_config.git_repository);
         cmd.arg("--nightly-branch").arg(git_config.nightly_branch);
 
-        builder.ci_env.force_coloring_in_ci(&mut cmd);
+        // FIXME: Move CiEnv back to bootstrap, it is only used here anyway
+        builder.ci_env.force_coloring_in_ci(&mut cmd.command);
 
         #[cfg(feature = "build-metrics")]
         builder.metrics.begin_test_suite(
@@ -2179,7 +2175,7 @@ impl BookTest {
             compiler.host,
         );
         let _time = helpers::timeit(builder);
-        let toolstate = if builder.run_delaying_failure(&mut rustbook_cmd) {
+        let toolstate = if rustbook_cmd.delay_failure().run(builder).is_success() {
             ToolState::TestPass
         } else {
             ToolState::TestFail
@@ -2312,7 +2308,7 @@ impl Step for ErrorIndex {
         let guard =
             builder.msg(Kind::Test, compiler.stage, "error-index", compiler.host, compiler.host);
         let _time = helpers::timeit(builder);
-        builder.run_quiet(&mut tool);
+        tool.capture().run(builder);
         drop(guard);
         // The tests themselves need to link to std, so make sure it is
         // available.
@@ -2341,11 +2337,11 @@ fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) ->
     let test_args = builder.config.test_args().join(" ");
     cmd.arg("--test-args").arg(test_args);
 
-    if builder.config.verbose_tests {
-        builder.run_delaying_failure(&mut cmd)
-    } else {
-        builder.run_quiet_delaying_failure(&mut cmd)
+    cmd = cmd.delay_failure();
+    if !builder.config.verbose_tests {
+        cmd = cmd.capture();
     }
+    cmd.run(builder).is_success()
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -2369,8 +2365,9 @@ impl Step for RustcGuide {
         builder.update_submodule(&relative_path);
 
         let src = builder.src.join(relative_path);
-        let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook);
-        let toolstate = if builder.run_delaying_failure(rustbook_cmd.arg("linkcheck").arg(&src)) {
+        let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook).delay_failure();
+        rustbook_cmd.arg("linkcheck").arg(&src);
+        let toolstate = if rustbook_cmd.run(builder).is_success() {
             ToolState::TestPass
         } else {
             ToolState::TestFail
@@ -2425,7 +2422,7 @@ impl Step for CrateLibrustc {
 /// Returns whether the test succeeded.
 #[allow(clippy::too_many_arguments)] // FIXME: reduce the number of args and remove this.
 fn run_cargo_test<'a>(
-    cargo: impl Into<Command>,
+    cargo: impl Into<BootstrapCommand>,
     libtest_args: &[&str],
     crates: &[String],
     primary_crate: &str,
@@ -2456,14 +2453,14 @@ fn run_cargo_test<'a>(
 
 /// Given a `cargo test` subcommand, pass it the appropriate test flags given a `builder`.
 fn prepare_cargo_test(
-    cargo: impl Into<Command>,
+    cargo: impl Into<BootstrapCommand>,
     libtest_args: &[&str],
     crates: &[String],
     primary_crate: &str,
     compiler: Compiler,
     target: TargetSelection,
     builder: &Builder<'_>,
-) -> Command {
+) -> BootstrapCommand {
     let mut cargo = cargo.into();
 
     // Propegate `--bless` if it has not already been set/unset
@@ -2874,19 +2871,19 @@ impl Step for RemoteCopyLibs {
 
         // Spawn the emulator and wait for it to come online
         let tool = builder.tool_exe(Tool::RemoteTestClient);
-        let mut cmd = Command::new(&tool);
+        let mut cmd = command(&tool);
         cmd.arg("spawn-emulator").arg(target.triple).arg(&server).arg(builder.tempdir());
         if let Some(rootfs) = builder.qemu_rootfs(target) {
             cmd.arg(rootfs);
         }
-        builder.run(&mut cmd);
+        cmd.run(builder);
 
         // Push all our dylibs to the emulator
         for f in t!(builder.sysroot_libdir(compiler, target).read_dir()) {
             let f = t!(f);
             let name = f.file_name().into_string().unwrap();
             if helpers::is_dylib(&name) {
-                builder.run(Command::new(&tool).arg("push").arg(f.path()));
+                builder.run(command(&tool).arg("push").arg(f.path()));
             }
         }
     }
@@ -2917,22 +2914,20 @@ impl Step for Distcheck {
         builder.ensure(dist::PlainSourceTarball);
         builder.ensure(dist::Src);
 
-        let mut cmd = Command::new("tar");
+        let mut cmd = command("tar");
         cmd.arg("-xf")
             .arg(builder.ensure(dist::PlainSourceTarball).tarball())
             .arg("--strip-components=1")
             .current_dir(&dir);
-        builder.run(&mut cmd);
+        cmd.run(builder);
         builder.run(
-            Command::new("./configure")
+            command("./configure")
                 .args(&builder.config.configure_args)
                 .arg("--enable-vendor")
                 .current_dir(&dir),
         );
         builder.run(
-            Command::new(helpers::make(&builder.config.build.triple))
-                .arg("check")
-                .current_dir(&dir),
+            command(helpers::make(&builder.config.build.triple)).arg("check").current_dir(&dir),
         );
 
         // Now make sure that rust-src has all of libstd's dependencies
@@ -2941,16 +2936,16 @@ impl Step for Distcheck {
         let _ = fs::remove_dir_all(&dir);
         t!(fs::create_dir_all(&dir));
 
-        let mut cmd = Command::new("tar");
+        let mut cmd = command("tar");
         cmd.arg("-xf")
             .arg(builder.ensure(dist::Src).tarball())
             .arg("--strip-components=1")
             .current_dir(&dir);
-        builder.run(&mut cmd);
+        cmd.run(builder);
 
         let toml = dir.join("rust-src/lib/rustlib/src/rust/library/std/Cargo.toml");
         builder.run(
-            Command::new(&builder.initial_cargo)
+            command(&builder.initial_cargo)
                 // Will read the libstd Cargo.toml
                 // which uses the unstable `public-dependency` feature.
                 .env("RUSTC_BOOTSTRAP", "1")
@@ -2976,17 +2971,22 @@ impl Step for Bootstrap {
         let compiler = builder.compiler(0, host);
         let _guard = builder.msg(Kind::Test, 0, "bootstrap", host, host);
 
-        let mut check_bootstrap = Command::new(builder.python());
+        // Some tests require cargo submodule to be present.
+        builder.build.update_submodule(Path::new("src/tools/cargo"));
+
+        let mut check_bootstrap = command(builder.python());
         check_bootstrap
             .args(["-m", "unittest", "bootstrap_test.py"])
             .env("BUILD_DIR", &builder.out)
             .env("BUILD_PLATFORM", builder.build.build.triple)
+            .env("BOOTSTRAP_TEST_RUSTC_BIN", &builder.initial_rustc)
+            .env("BOOTSTRAP_TEST_CARGO_BIN", &builder.initial_cargo)
             .current_dir(builder.src.join("src/bootstrap/"));
         // NOTE: we intentionally don't pass test_args here because the args for unittest and cargo test are mutually incompatible.
         // Use `python -m unittest` manually if you want to pass arguments.
-        builder.run_delaying_failure(&mut check_bootstrap);
+        check_bootstrap.delay_failure().run(builder);
 
-        let mut cmd = Command::new(&builder.initial_cargo);
+        let mut cmd = command(&builder.initial_cargo);
         cmd.arg("test")
             .args(["--features", "bootstrap-self-test"])
             .current_dir(builder.src.join("src/bootstrap"))
@@ -3061,7 +3061,7 @@ impl Step for TierCheck {
             self.compiler.host,
             self.compiler.host,
         );
-        builder.run_delaying_failure(&mut cargo.into());
+        BootstrapCommand::from(cargo).delay_failure().run(builder);
     }
 }
 
@@ -3137,8 +3137,7 @@ impl Step for RustInstaller {
             return;
         }
 
-        let mut cmd =
-            std::process::Command::new(builder.src.join("src/tools/rust-installer/test.sh"));
+        let mut cmd = command(builder.src.join("src/tools/rust-installer/test.sh"));
         let tmpdir = testdir(builder, compiler.host).join("rust-installer");
         let _ = std::fs::remove_dir_all(&tmpdir);
         let _ = std::fs::create_dir_all(&tmpdir);
@@ -3147,7 +3146,7 @@ impl Step for RustInstaller {
         cmd.env("CARGO", &builder.initial_cargo);
         cmd.env("RUSTC", &builder.initial_rustc);
         cmd.env("TMP_DIR", &tmpdir);
-        builder.run_delaying_failure(&mut cmd);
+        cmd.delay_failure().run(builder);
     }
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
@@ -3341,8 +3340,7 @@ impl Step for CodegenCranelift {
             .arg("testsuite.extended_sysroot");
         cargo.args(builder.config.test_args());
 
-        let mut cmd: Command = cargo.into();
-        builder.run_cmd(BootstrapCommand::from(&mut cmd).fail_fast());
+        cargo.into_cmd().run(builder);
     }
 }
 
@@ -3467,7 +3465,6 @@ impl Step for CodegenGCC {
             .arg("--std-tests");
         cargo.args(builder.config.test_args());
 
-        let mut cmd: Command = cargo.into();
-        builder.run_cmd(BootstrapCommand::from(&mut cmd).fail_fast());
+        cargo.into_cmd().run(builder);
     }
 }
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index 613484788b6..ad92a01bce7 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -1,7 +1,6 @@
 use std::env;
 use std::fs;
 use std::path::{Path, PathBuf};
-use std::process::Command;
 
 use crate::core::build_steps::compile;
 use crate::core::build_steps::toolstate::ToolState;
@@ -9,7 +8,7 @@ use crate::core::builder;
 use crate::core::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step};
 use crate::core::config::TargetSelection;
 use crate::utils::channel::GitInfo;
-use crate::utils::helpers::output;
+use crate::utils::exec::{command, BootstrapCommand};
 use crate::utils::helpers::{add_dylib_path, exe, t};
 use crate::Compiler;
 use crate::Mode;
@@ -32,6 +31,8 @@ struct ToolBuild {
     extra_features: Vec<String>,
     /// Nightly-only features that are allowed (comma-separated list).
     allow_features: &'static str,
+    /// Additional arguments to pass to the `cargo` invocation.
+    cargo_args: Vec<String>,
 }
 
 impl Builder<'_> {
@@ -100,6 +101,7 @@ impl Step for ToolBuild {
         if !self.allow_features.is_empty() {
             cargo.allow_features(self.allow_features);
         }
+        cargo.args(self.cargo_args);
         let _guard = builder.msg_tool(
             Kind::Build,
             self.mode,
@@ -126,10 +128,7 @@ impl Step for ToolBuild {
             if tool == "tidy" {
                 tool = "rust-tidy";
             }
-            let cargo_out = builder.cargo_out(compiler, self.mode, target).join(exe(tool, target));
-            let bin = builder.tools_dir(compiler).join(exe(tool, target));
-            builder.copy_link(&cargo_out, &bin);
-            bin
+            copy_link_tool_bin(builder, self.compiler, self.target, self.mode, tool)
         }
     }
 }
@@ -211,9 +210,31 @@ pub fn prepare_tool_cargo(
     // See https://github.com/rust-lang/rust/issues/116538
     cargo.rustflag("-Zunstable-options");
 
+    // `-Zon-broken-pipe=kill` breaks cargo tests
+    if !path.ends_with("cargo") {
+        // If the output is piped to e.g. `head -n1` we want the process to be killed,
+        // rather than having an error bubble up and cause a panic.
+        cargo.rustflag("-Zon-broken-pipe=kill");
+    }
+
     cargo
 }
 
+/// Links a built tool binary with the given `name` from the build directory to the
+/// tools directory.
+fn copy_link_tool_bin(
+    builder: &Builder<'_>,
+    compiler: Compiler,
+    target: TargetSelection,
+    mode: Mode,
+    name: &str,
+) -> PathBuf {
+    let cargo_out = builder.cargo_out(compiler, mode, target).join(exe(name, target));
+    let bin = builder.tools_dir(compiler).join(exe(name, target));
+    builder.copy_link(&cargo_out, &bin);
+    bin
+}
+
 macro_rules! bootstrap_tool {
     ($(
         $name:ident, $path:expr, $tool_name:expr
@@ -223,6 +244,7 @@ macro_rules! bootstrap_tool {
         ;
     )+) => {
         #[derive(PartialEq, Eq, Clone)]
+        #[allow(dead_code)]
         pub enum Tool {
             $(
                 $name,
@@ -283,6 +305,7 @@ macro_rules! bootstrap_tool {
                     },
                     extra_features: vec![],
                     allow_features: concat!($($allow_features)*),
+                    cargo_args: vec![]
                 })
             }
         }
@@ -313,6 +336,7 @@ bootstrap_tool!(
     GenerateWindowsSys, "src/tools/generate-windows-sys", "generate-windows-sys";
     RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = "test";
     CoverageDump, "src/tools/coverage-dump", "coverage-dump";
+    RustcPerfWrapper, "src/tools/rustc-perf-wrapper", "rustc-perf-wrapper";
 );
 
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
@@ -349,22 +373,72 @@ impl Step for OptimizedDist {
             source_type: SourceType::InTree,
             extra_features: Vec::new(),
             allow_features: "",
+            cargo_args: Vec::new(),
         })
     }
 }
 
+/// The [rustc-perf](https://github.com/rust-lang/rustc-perf) benchmark suite, which is added
+/// as a submodule at `src/tools/rustc-perf`.
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+pub struct RustcPerf {
+    pub compiler: Compiler,
+    pub target: TargetSelection,
+}
+
+impl Step for RustcPerf {
+    /// Path to the built `collector` binary.
+    type Output = PathBuf;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.path("src/tools/rustc-perf")
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(RustcPerf {
+            compiler: run.builder.compiler(0, run.builder.config.build),
+            target: run.target,
+        });
+    }
+
+    fn run(self, builder: &Builder<'_>) -> PathBuf {
+        // We need to ensure the rustc-perf submodule is initialized.
+        builder.update_submodule(Path::new("src/tools/rustc-perf"));
+
+        let tool = ToolBuild {
+            compiler: self.compiler,
+            target: self.target,
+            tool: "collector",
+            mode: Mode::ToolBootstrap,
+            path: "src/tools/rustc-perf",
+            source_type: SourceType::Submodule,
+            extra_features: Vec::new(),
+            allow_features: "",
+            // Only build the collector package, which is used for benchmarking through
+            // a CLI.
+            cargo_args: vec!["-p".to_string(), "collector".to_string()],
+        };
+        let collector_bin = builder.ensure(tool.clone());
+        // We also need to symlink the `rustc-fake` binary to the corresponding directory,
+        // because `collector` expects it in the same directory.
+        copy_link_tool_bin(builder, tool.compiler, tool.target, tool.mode, "rustc-fake");
+
+        collector_bin
+    }
+}
+
 #[derive(Debug, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
 pub struct ErrorIndex {
     pub compiler: Compiler,
 }
 
 impl ErrorIndex {
-    pub fn command(builder: &Builder<'_>) -> Command {
+    pub fn command(builder: &Builder<'_>) -> BootstrapCommand {
         // Error-index-generator links with the rustdoc library, so we need to add `rustc_lib_paths`
         // for rustc_private and libLLVM.so, and `sysroot_lib` for libstd, etc.
         let host = builder.config.build;
         let compiler = builder.compiler_for(builder.top_stage, host, host);
-        let mut cmd = Command::new(builder.ensure(ErrorIndex { compiler }));
+        let mut cmd = command(builder.ensure(ErrorIndex { compiler }));
         let mut dylib_paths = builder.rustc_lib_paths(compiler);
         dylib_paths.push(PathBuf::from(&builder.sysroot_libdir(compiler, compiler.host)));
         add_dylib_path(dylib_paths, &mut cmd);
@@ -403,6 +477,7 @@ impl Step for ErrorIndex {
             source_type: SourceType::InTree,
             extra_features: Vec::new(),
             allow_features: "",
+            cargo_args: Vec::new(),
         })
     }
 }
@@ -437,6 +512,7 @@ impl Step for RemoteTestServer {
             source_type: SourceType::InTree,
             extra_features: Vec::new(),
             allow_features: "",
+            cargo_args: Vec::new(),
         })
     }
 }
@@ -476,24 +552,23 @@ impl Step for Rustdoc {
             return builder.initial_rustc.with_file_name(exe("rustdoc", target_compiler.host));
         }
         let target = target_compiler.host;
-        // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise
-        // we'd have stageN/bin/rustc and stageN/bin/rustdoc be effectively different stage
-        // compilers, which isn't what we want. Rustdoc should be linked in the same way as the
-        // rustc compiler it's paired with, so it must be built with the previous stage compiler.
-        let build_compiler = builder.compiler(target_compiler.stage - 1, builder.config.build);
+
+        let build_compiler = if builder.download_rustc() && target_compiler.stage == 1 {
+            // We already have the stage 1 compiler, we don't need to cut the stage.
+            builder.compiler(target_compiler.stage, builder.config.build)
+        } else {
+            // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise
+            // we'd have stageN/bin/rustc and stageN/bin/rustdoc be effectively different stage
+            // compilers, which isn't what we want. Rustdoc should be linked in the same way as the
+            // rustc compiler it's paired with, so it must be built with the previous stage compiler.
+            builder.compiler(target_compiler.stage - 1, builder.config.build)
+        };
 
         // When using `download-rustc` and a stage0 build_compiler, copying rustc doesn't actually
         // build stage0 libstd (because the libstd in sysroot has the wrong ABI). Explicitly build
         // it.
         builder.ensure(compile::Std::new(build_compiler, target_compiler.host));
         builder.ensure(compile::Rustc::new(build_compiler, target_compiler.host));
-        // NOTE: this implies that `download-rustc` is pretty useless when compiling with the stage0
-        // compiler, since you do just as much work.
-        if !builder.config.dry_run() && builder.download_rustc() && build_compiler.stage == 0 {
-            println!(
-                "WARNING: `download-rustc` does nothing when building stage1 tools; consider using `--stage 2` instead"
-            );
-        }
 
         // The presence of `target_compiler` ensures that the necessary libraries (codegen backends,
         // compiler libraries, ...) are built. Rustdoc does not require the presence of any
@@ -507,7 +582,8 @@ impl Step for Rustdoc {
             features.push("jemalloc".to_string());
         }
 
-        let mut cargo = prepare_tool_cargo(
+        // NOTE: Never modify the rustflags here, it breaks the build cache for other tools!
+        let cargo = prepare_tool_cargo(
             builder,
             build_compiler,
             Mode::ToolRustc,
@@ -518,11 +594,6 @@ impl Step for Rustdoc {
             features.as_slice(),
         );
 
-        // If the rustdoc output is piped to e.g. `head -n1` we want the process
-        // to be killed, rather than having an error bubble up and cause a
-        // panic.
-        cargo.rustflag("-Zon-broken-pipe=kill");
-
         let _guard = builder.msg_tool(
             Kind::Build,
             Mode::ToolRustc,
@@ -531,7 +602,7 @@ impl Step for Rustdoc {
             &self.compiler.host,
             &target,
         );
-        builder.run(&mut cargo.into());
+        cargo.into_cmd().run(builder);
 
         // Cargo adds a number of paths to the dylib search path on windows, which results in
         // the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool"
@@ -586,6 +657,8 @@ impl Step for Cargo {
     }
 
     fn run(self, builder: &Builder<'_>) -> PathBuf {
+        builder.build.update_submodule(Path::new("src/tools/cargo"));
+
         builder.ensure(ToolBuild {
             compiler: self.compiler,
             target: self.target,
@@ -595,6 +668,7 @@ impl Step for Cargo {
             source_type: SourceType::Submodule,
             extra_features: Vec::new(),
             allow_features: "",
+            cargo_args: Vec::new(),
         })
     }
 }
@@ -622,6 +696,7 @@ impl Step for LldWrapper {
             source_type: SourceType::InTree,
             extra_features: Vec::new(),
             allow_features: "",
+            cargo_args: Vec::new(),
         })
     }
 }
@@ -670,6 +745,7 @@ impl Step for RustAnalyzer {
             extra_features: vec!["in-rust-tree".to_owned()],
             source_type: SourceType::InTree,
             allow_features: RustAnalyzer::ALLOW_FEATURES,
+            cargo_args: Vec::new(),
         })
     }
 }
@@ -717,6 +793,7 @@ impl Step for RustAnalyzerProcMacroSrv {
             extra_features: vec!["in-rust-tree".to_owned()],
             source_type: SourceType::InTree,
             allow_features: RustAnalyzer::ALLOW_FEATURES,
+            cargo_args: Vec::new(),
         });
 
         // Copy `rust-analyzer-proc-macro-srv` to `<sysroot>/libexec/`
@@ -780,7 +857,7 @@ impl Step for LlvmBitcodeLinker {
             &self.extra_features,
         );
 
-        builder.run(&mut cargo.into());
+        cargo.into_cmd().run(builder);
 
         let tool_out = builder
             .cargo_out(self.compiler, Mode::ToolRustc, self.target)
@@ -835,20 +912,20 @@ impl Step for LibcxxVersionTool {
             }
 
             let compiler = builder.cxx(self.target).unwrap();
-            let mut cmd = Command::new(compiler);
+            let mut cmd = command(compiler);
 
             cmd.arg("-o")
                 .arg(&executable)
                 .arg(builder.src.join("src/tools/libcxx-version/main.cpp"));
 
-            builder.run_cmd(&mut cmd);
+            cmd.run(builder);
 
             if !executable.exists() {
                 panic!("Something went wrong. {} is not present", executable.display());
             }
         }
 
-        let version_output = output(&mut Command::new(executable));
+        let version_output = command(executable).capture_stdout().run(builder).stdout();
 
         let version_str = version_output.split_once("version:").unwrap().1;
         let version = version_str.trim().parse::<usize>().unwrap();
@@ -923,6 +1000,7 @@ macro_rules! tool_extended {
                     extra_features: $sel.extra_features,
                     source_type: SourceType::InTree,
                     allow_features: concat!($($allow_features)*),
+                    cargo_args: vec![]
                 });
 
                 if (false $(|| !$add_bins_to_sysroot.is_empty())?) && $sel.compiler.stage > 0 {
@@ -968,10 +1046,10 @@ tool_extended!((self, builder),
 );
 
 impl<'a> Builder<'a> {
-    /// Gets a `Command` which is ready to run `tool` in `stage` built for
+    /// Gets a `BootstrapCommand` which is ready to run `tool` in `stage` built for
     /// `host`.
-    pub fn tool_cmd(&self, tool: Tool) -> Command {
-        let mut cmd = Command::new(self.tool_exe(tool));
+    pub fn tool_cmd(&self, tool: Tool) -> BootstrapCommand {
+        let mut cmd = command(self.tool_exe(tool));
         let compiler = self.compiler(0, self.config.build);
         let host = &compiler.host;
         // Prepares the `cmd` provided to be able to run the `compiler` provided.
diff --git a/src/bootstrap/src/core/build_steps/toolstate.rs b/src/bootstrap/src/core/build_steps/toolstate.rs
index 9e6d03349b5..e3e7931a5a2 100644
--- a/src/bootstrap/src/core/build_steps/toolstate.rs
+++ b/src/bootstrap/src/core/build_steps/toolstate.rs
@@ -101,8 +101,13 @@ fn print_error(tool: &str, submodule: &str) {
 
 fn check_changed_files(toolstates: &HashMap<Box<str>, ToolState>) {
     // Changed files
-    let output =
-        helpers::git(None).arg("diff").arg("--name-status").arg("HEAD").arg("HEAD^").output();
+    let output = helpers::git(None)
+        .arg("diff")
+        .arg("--name-status")
+        .arg("HEAD")
+        .arg("HEAD^")
+        .command
+        .output();
     let output = match output {
         Ok(o) => o,
         Err(e) => {
@@ -324,6 +329,7 @@ fn checkout_toolstate_repo() {
         .arg("--depth=1")
         .arg(toolstate_repo())
         .arg(TOOLSTATE_DIR)
+        .command
         .status();
     let success = match status {
         Ok(s) => s.success(),
@@ -337,7 +343,8 @@ fn checkout_toolstate_repo() {
 /// Sets up config and authentication for modifying the toolstate repo.
 fn prepare_toolstate_config(token: &str) {
     fn git_config(key: &str, value: &str) {
-        let status = helpers::git(None).arg("config").arg("--global").arg(key).arg(value).status();
+        let status =
+            helpers::git(None).arg("config").arg("--global").arg(key).arg(value).command.status();
         let success = match status {
             Ok(s) => s.success(),
             Err(_) => false,
@@ -406,6 +413,7 @@ fn commit_toolstate_change(current_toolstate: &ToolstateData) {
             .arg("-a")
             .arg("-m")
             .arg(&message)
+            .command
             .status());
         if !status.success() {
             success = true;
@@ -416,6 +424,7 @@ fn commit_toolstate_change(current_toolstate: &ToolstateData) {
             .arg("push")
             .arg("origin")
             .arg("master")
+            .command
             .status());
         // If we successfully push, exit.
         if status.success() {
@@ -428,12 +437,14 @@ fn commit_toolstate_change(current_toolstate: &ToolstateData) {
             .arg("fetch")
             .arg("origin")
             .arg("master")
+            .command
             .status());
         assert!(status.success());
         let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR)))
             .arg("reset")
             .arg("--hard")
             .arg("origin/master")
+            .command
             .status());
         assert!(status.success());
     }
@@ -449,7 +460,7 @@ fn commit_toolstate_change(current_toolstate: &ToolstateData) {
 /// `publish_toolstate.py` script if the PR passes all tests and is merged to
 /// master.
 fn publish_test_results(current_toolstate: &ToolstateData) {
-    let commit = t!(helpers::git(None).arg("rev-parse").arg("HEAD").output());
+    let commit = t!(helpers::git(None).arg("rev-parse").arg("HEAD").command.output());
     let commit = t!(String::from_utf8(commit.stdout));
 
     let toolstate_serialized = t!(serde_json::to_string(&current_toolstate));
diff --git a/src/bootstrap/src/core/build_steps/vendor.rs b/src/bootstrap/src/core/build_steps/vendor.rs
index 68f1b1bef3f..62342ee4792 100644
--- a/src/bootstrap/src/core/build_steps/vendor.rs
+++ b/src/bootstrap/src/core/build_steps/vendor.rs
@@ -1,6 +1,6 @@
 use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
-use std::path::PathBuf;
-use std::process::Command;
+use crate::utils::exec::command;
+use std::path::{Path, PathBuf};
 
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub(crate) struct Vendor {
@@ -27,13 +27,16 @@ impl Step for Vendor {
     }
 
     fn run(self, builder: &Builder<'_>) -> Self::Output {
-        let mut cmd = Command::new(&builder.initial_cargo);
+        let mut cmd = command(&builder.initial_cargo);
         cmd.arg("vendor");
 
         if self.versioned_dirs {
             cmd.arg("--versioned-dirs");
         }
 
+        // cargo submodule must be present for `x vendor` to work.
+        builder.build.update_submodule(Path::new("src/tools/cargo"));
+
         // Sync these paths by default.
         for p in [
             "src/tools/cargo/Cargo.toml",
@@ -56,6 +59,6 @@ impl Step for Vendor {
 
         cmd.current_dir(self.root_dir);
 
-        builder.run(&mut cmd);
+        cmd.run(builder);
     }
 }
diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs
index 3c4806a1311..65cc1fa7478 100644
--- a/src/bootstrap/src/core/builder.rs
+++ b/src/bootstrap/src/core/builder.rs
@@ -4,13 +4,11 @@ use std::collections::BTreeSet;
 use std::env;
 use std::ffi::{OsStr, OsString};
 use std::fmt::{Debug, Write};
-use std::fs::{self, File};
+use std::fs;
 use std::hash::Hash;
-use std::io::{BufRead, BufReader};
 use std::ops::Deref;
 use std::path::{Path, PathBuf};
-use std::process::Command;
-use std::sync::OnceLock;
+use std::sync::LazyLock;
 use std::time::{Duration, Instant};
 
 use crate::core::build_steps::tool::{self, SourceType};
@@ -22,15 +20,14 @@ use crate::core::config::{DryRun, SplitDebuginfo, TargetSelection};
 use crate::prepare_behaviour_dump_dir;
 use crate::utils::cache::Cache;
 use crate::utils::helpers::{self, add_dylib_path, add_link_lib_path, exe, linker_args};
-use crate::utils::helpers::{check_cfg_arg, libdir, linker_flags, output, t, LldThreads};
+use crate::utils::helpers::{check_cfg_arg, libdir, linker_flags, t, LldThreads};
 use crate::EXTRA_CHECK_CFGS;
 use crate::{Build, CLang, Crate, DocTests, GitRepo, Mode};
 
+use crate::utils::exec::{command, BootstrapCommand};
 pub use crate::Compiler;
 
 use clap::ValueEnum;
-// FIXME: replace with std::lazy after it gets stabilized and reaches beta
-use once_cell::sync::Lazy;
 
 #[cfg(test)]
 mod tests;
@@ -274,7 +271,7 @@ impl PathSet {
     /// This is used for `StepDescription::krate`, which passes all matching crates at once to
     /// `Step::make_run`, rather than calling it many times with a single crate.
     /// See `tests.rs` for examples.
-    fn intersection_removing_matches(&self, needles: &mut Vec<&Path>, module: Kind) -> PathSet {
+    fn intersection_removing_matches(&self, needles: &mut Vec<PathBuf>, module: Kind) -> PathSet {
         let mut check = |p| {
             for (i, n) in needles.iter().enumerate() {
                 let matched = Self::check(p, n, module);
@@ -346,7 +343,7 @@ const PATH_REMAP: &[(&str, &[&str])] = &[
     ),
 ];
 
-fn remap_paths(paths: &mut Vec<&Path>) {
+fn remap_paths(paths: &mut Vec<PathBuf>) {
     let mut remove = vec![];
     let mut add = vec![];
     for (i, path) in paths.iter().enumerate().filter_map(|(i, path)| path.to_str().map(|s| (i, s)))
@@ -355,7 +352,7 @@ fn remap_paths(paths: &mut Vec<&Path>) {
             // Remove leading and trailing slashes so `tests/` and `tests` are equivalent
             if path.trim_matches(std::path::is_separator) == search {
                 remove.push(i);
-                add.extend(replace.iter().map(Path::new));
+                add.extend(replace.iter().map(PathBuf::from));
                 break;
             }
         }
@@ -438,8 +435,25 @@ impl StepDescription {
             }
         }
 
-        // strip CurDir prefix if present
-        let mut paths: Vec<_> = paths.iter().map(|p| p.strip_prefix(".").unwrap_or(p)).collect();
+        // Attempt to resolve paths to be relative to the builder source directory.
+        let mut paths: Vec<PathBuf> = paths
+            .iter()
+            .map(|p| {
+                // If the path does not exist, it may represent the name of a Step, such as `tidy` in `x test tidy`
+                if !p.exists() {
+                    return p.clone();
+                }
+
+                // Make the path absolute, strip the prefix, and convert to a PathBuf.
+                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);
+                    }
+                }
+            })
+            .collect();
 
         remap_paths(&mut paths);
 
@@ -483,7 +497,7 @@ impl StepDescription {
 
 enum ReallyDefault<'a> {
     Bool(bool),
-    Lazy(Lazy<bool, Box<dyn Fn() -> bool + 'a>>),
+    Lazy(LazyLock<bool, Box<dyn Fn() -> bool + 'a>>),
 }
 
 pub struct ShouldRun<'a> {
@@ -514,7 +528,7 @@ impl<'a> ShouldRun<'a> {
     }
 
     pub fn lazy_default_condition(mut self, lazy_cond: Box<dyn Fn() -> bool + 'a>) -> Self {
-        self.is_really_default = ReallyDefault::Lazy(Lazy::new(lazy_cond));
+        self.is_really_default = ReallyDefault::Lazy(LazyLock::new(lazy_cond));
         self
     }
 
@@ -577,7 +591,7 @@ impl<'a> ShouldRun<'a> {
     ///
     /// [`path`]: ShouldRun::path
     pub fn paths(mut self, paths: &[&str]) -> Self {
-        let submodules_paths = self.builder.get_all_submodules();
+        let submodules_paths = build_helper::util::parse_gitmodules(&self.builder.src);
 
         self.paths.insert(PathSet::Set(
             paths
@@ -629,7 +643,7 @@ impl<'a> ShouldRun<'a> {
     /// (for now, just `all_krates` and `paths`, but we may want to add an `aliases` function in the future?)
     fn pathset_for_paths_removing_matches(
         &self,
-        paths: &mut Vec<&Path>,
+        paths: &mut Vec<PathBuf>,
         kind: Kind,
     ) -> Vec<PathSet> {
         let mut sets = vec![];
@@ -666,6 +680,7 @@ pub enum Kind {
     Setup,
     Suggest,
     Vendor,
+    Perf,
 }
 
 impl Kind {
@@ -687,6 +702,7 @@ impl Kind {
             Kind::Setup => "setup",
             Kind::Suggest => "suggest",
             Kind::Vendor => "vendor",
+            Kind::Perf => "perf",
         }
     }
 
@@ -698,6 +714,7 @@ impl Kind {
             Kind::Run => "Running",
             Kind::Suggest => "Suggesting",
             Kind::Clippy => "Linting",
+            Kind::Perf => "Profiling & benchmarking",
             _ => {
                 let title_letter = self.as_str()[0..1].to_ascii_uppercase();
                 return format!("{title_letter}{}ing", &self.as_str()[1..]);
@@ -749,7 +766,8 @@ impl<'a> Builder<'a> {
                 tool::RustdocGUITest,
                 tool::OptimizedDist,
                 tool::CoverageDump,
-                tool::LlvmBitcodeLinker
+                tool::LlvmBitcodeLinker,
+                tool::RustcPerf,
             ),
             Kind::Clippy => describe!(
                 clippy::Std,
@@ -945,7 +963,7 @@ impl<'a> Builder<'a> {
             Kind::Clean => describe!(clean::CleanAll, clean::Rustc, clean::Std),
             Kind::Vendor => describe!(vendor::Vendor),
             // special-cased in Build::build()
-            Kind::Format | Kind::Suggest => vec![],
+            Kind::Format | Kind::Suggest | Kind::Perf => vec![],
         }
     }
 
@@ -1017,6 +1035,7 @@ impl<'a> Builder<'a> {
                 path.as_ref().map_or([].as_slice(), |path| std::slice::from_ref(path)),
             ),
             Subcommand::Vendor { .. } => (Kind::Vendor, &paths[..]),
+            Subcommand::Perf { .. } => (Kind::Perf, &paths[..]),
         };
 
         Self::new_internal(build, kind, paths.to_owned())
@@ -1197,7 +1216,7 @@ impl<'a> Builder<'a> {
 
     /// Adds the compiler's directory of dynamic libraries to `cmd`'s dynamic
     /// library lookup path.
-    pub fn add_rustc_lib_path(&self, compiler: Compiler, cmd: &mut Command) {
+    pub fn add_rustc_lib_path(&self, compiler: Compiler, cmd: &mut BootstrapCommand) {
         // 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.
@@ -1230,11 +1249,11 @@ impl<'a> Builder<'a> {
         self.ensure(tool::Rustdoc { compiler })
     }
 
-    pub fn cargo_clippy_cmd(&self, run_compiler: Compiler) -> Command {
+    pub fn cargo_clippy_cmd(&self, run_compiler: Compiler) -> BootstrapCommand {
         if run_compiler.stage == 0 {
             // `ensure(Clippy { stage: 0 })` *builds* clippy with stage0, it doesn't use the beta clippy.
             let cargo_clippy = self.build.config.download_clippy();
-            let mut cmd = Command::new(cargo_clippy);
+            let mut cmd = command(cargo_clippy);
             cmd.env("CARGO", &self.initial_cargo);
             return cmd;
         }
@@ -1253,13 +1272,13 @@ impl<'a> Builder<'a> {
         let mut dylib_path = helpers::dylib_path();
         dylib_path.insert(0, self.sysroot(run_compiler).join("lib"));
 
-        let mut cmd = Command::new(cargo_clippy);
+        let mut cmd = command(cargo_clippy);
         cmd.env(helpers::dylib_path_var(), env::join_paths(&dylib_path).unwrap());
         cmd.env("CARGO", &self.initial_cargo);
         cmd
     }
 
-    pub fn cargo_miri_cmd(&self, run_compiler: Compiler) -> Command {
+    pub fn cargo_miri_cmd(&self, run_compiler: Compiler) -> BootstrapCommand {
         assert!(run_compiler.stage > 0, "miri can not be invoked at stage 0");
         let build_compiler = self.compiler(run_compiler.stage - 1, self.build.build);
 
@@ -1275,7 +1294,7 @@ impl<'a> Builder<'a> {
             extra_features: Vec::new(),
         });
         // Invoke cargo-miri, make sure it can find miri and cargo.
-        let mut cmd = Command::new(cargo_miri);
+        let mut cmd = command(cargo_miri);
         cmd.env("MIRI", &miri);
         cmd.env("CARGO", &self.initial_cargo);
         // Need to add the `run_compiler` libs. Those are the libs produces *by* `build_compiler`,
@@ -1290,8 +1309,8 @@ impl<'a> Builder<'a> {
         cmd
     }
 
-    pub fn rustdoc_cmd(&self, compiler: Compiler) -> Command {
-        let mut cmd = Command::new(self.bootstrap_out.join("rustdoc"));
+    pub fn rustdoc_cmd(&self, compiler: Compiler) -> BootstrapCommand {
+        let mut cmd = command(self.bootstrap_out.join("rustdoc"));
         cmd.env("RUSTC_STAGE", compiler.stage.to_string())
             .env("RUSTC_SYSROOT", self.sysroot(compiler))
             // Note that this is *not* the sysroot_libdir because rustdoc must be linked
@@ -1332,7 +1351,7 @@ impl<'a> Builder<'a> {
         mode: Mode,
         target: TargetSelection,
         cmd: &str, // FIXME make this properly typed
-    ) -> Command {
+    ) -> BootstrapCommand {
         let mut cargo;
         if cmd == "clippy" {
             cargo = self.cargo_clippy_cmd(compiler);
@@ -1345,7 +1364,7 @@ impl<'a> Builder<'a> {
             cargo = self.cargo_miri_cmd(compiler);
             cargo.arg("miri").arg(subcmd);
         } else {
-            cargo = Command::new(&self.initial_cargo);
+            cargo = command(&self.initial_cargo);
             cargo.arg(cmd);
         }
 
@@ -1898,7 +1917,8 @@ impl<'a> Builder<'a> {
         // platform-specific environment variable as a workaround.
         if mode == Mode::ToolRustc || mode == Mode::Codegen {
             if let Some(llvm_config) = self.llvm_config(target) {
-                let llvm_libdir = output(Command::new(llvm_config).arg("--libdir"));
+                let llvm_libdir =
+                    command(llvm_config).capture_stdout().arg("--libdir").run(self).stdout();
                 add_link_lib_path(vec![llvm_libdir.trim().into()], &mut cargo);
             }
         }
@@ -2084,7 +2104,7 @@ impl<'a> Builder<'a> {
         // Try to use a sysroot-relative bindir, in case it was configured absolutely.
         cargo.env("RUSTC_INSTALL_BINDIR", self.config.bindir_relative());
 
-        self.ci_env.force_coloring_in_ci(&mut cargo);
+        self.ci_env.force_coloring_in_ci(&mut cargo.command);
 
         // When we build Rust dylibs they're all intended for intermediate
         // usage, so make sure we pass the -Cprefer-dynamic flag instead of
@@ -2221,28 +2241,6 @@ impl<'a> Builder<'a> {
         out
     }
 
-    /// Return paths of all submodules.
-    pub fn get_all_submodules(&self) -> &[String] {
-        static SUBMODULES_PATHS: OnceLock<Vec<String>> = OnceLock::new();
-
-        let init_submodules_paths = |src: &PathBuf| {
-            let file = File::open(src.join(".gitmodules")).unwrap();
-
-            let mut submodules_paths = vec![];
-            for line in BufReader::new(file).lines().map_while(Result::ok) {
-                let line = line.trim();
-                if line.starts_with("path") {
-                    let actual_path = line.split(' ').last().expect("Couldn't get value of path");
-                    submodules_paths.push(actual_path.to_owned());
-                }
-            }
-
-            submodules_paths
-        };
-
-        SUBMODULES_PATHS.get_or_init(|| init_submodules_paths(&self.src))
-    }
-
     /// Ensure that a given step is built *only if it's supposed to be built by default*, returning
     /// its output. This will cache the step, so it's safe (and good!) to call this as often as
     /// needed to ensure that all dependencies are build.
@@ -2375,7 +2373,7 @@ impl HostFlags {
 
 #[derive(Debug)]
 pub struct Cargo {
-    command: Command,
+    command: BootstrapCommand,
     compiler: Compiler,
     target: TargetSelection,
     rustflags: Rustflags,
@@ -2399,6 +2397,10 @@ impl Cargo {
         cargo
     }
 
+    pub fn into_cmd(self) -> BootstrapCommand {
+        self.into()
+    }
+
     /// Same as `Cargo::new` except this one doesn't configure the linker with `Cargo::configure_linker`
     pub fn new_for_mir_opt_tests(
         builder: &Builder<'_>,
@@ -2523,7 +2525,7 @@ impl Cargo {
 
         if let Some(target_linker) = builder.linker(target) {
             let target = crate::envify(&target.triple);
-            self.command.env(&format!("CARGO_TARGET_{target}_LINKER"), target_linker);
+            self.command.env(format!("CARGO_TARGET_{target}_LINKER"), target_linker);
         }
         // We want to set -Clinker using Cargo, therefore we only call `linker_flags` and not
         // `linker_args` here.
@@ -2600,8 +2602,8 @@ impl Cargo {
     }
 }
 
-impl From<Cargo> for Command {
-    fn from(mut cargo: Cargo) -> Command {
+impl From<Cargo> for BootstrapCommand {
+    fn from(mut cargo: Cargo) -> BootstrapCommand {
         let rustflags = &cargo.rustflags.0;
         if !rustflags.is_empty() {
             cargo.command.env("RUSTFLAGS", rustflags);
@@ -2620,7 +2622,6 @@ impl From<Cargo> for Command {
         if !cargo.allow_features.is_empty() {
             cargo.command.env("RUSTC_ALLOW_FEATURES", cargo.allow_features);
         }
-
         cargo.command
     }
 }
diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs
index 276fd0b11d6..aa119b8c699 100644
--- a/src/bootstrap/src/core/builder/tests.rs
+++ b/src/bootstrap/src/core/builder/tests.rs
@@ -122,11 +122,14 @@ fn test_intersection() {
         PathSet::Set(paths.into_iter().map(|p| TaskPath { path: p.into(), kind: None }).collect())
     };
     let library_set = set(&["library/core", "library/alloc", "library/std"]);
-    let mut command_paths =
-        vec![Path::new("library/core"), Path::new("library/alloc"), Path::new("library/stdarch")];
+    let mut command_paths = vec![
+        PathBuf::from("library/core"),
+        PathBuf::from("library/alloc"),
+        PathBuf::from("library/stdarch"),
+    ];
     let subset = library_set.intersection_removing_matches(&mut command_paths, Kind::Build);
     assert_eq!(subset, set(&["library/core", "library/alloc"]),);
-    assert_eq!(command_paths, vec![Path::new("library/stdarch")]);
+    assert_eq!(command_paths, vec![PathBuf::from("library/stdarch")]);
 }
 
 #[test]
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 0438dee7241..2d54a84331f 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -1259,6 +1259,7 @@ impl Config {
         cmd.arg("rev-parse").arg("--show-cdup");
         // Discard stderr because we expect this to fail when building from a tarball.
         let output = cmd
+            .command
             .stderr(std::process::Stdio::null())
             .output()
             .ok()
@@ -1329,6 +1330,17 @@ impl Config {
             TomlConfig::default()
         };
 
+        if cfg!(test) {
+            // When configuring bootstrap for tests, make sure to set the rustc and Cargo to the
+            // same ones used to call the tests (if custom ones are not defined in the toml). If we
+            // don't do that, bootstrap will use its own detection logic to find a suitable rustc
+            // and Cargo, which doesn't work when the caller is specìfying a custom local rustc or
+            // Cargo in their config.toml.
+            let build = toml.build.get_or_insert_with(Default::default);
+            build.rustc = build.rustc.take().or(std::env::var_os("RUSTC").map(|p| p.into()));
+            build.cargo = build.cargo.take().or(std::env::var_os("CARGO").map(|p| p.into()));
+        }
+
         if let Some(include) = &toml.profile {
             // Allows creating alias for profile names, allowing
             // profiles to be renamed while maintaining back compatibility
@@ -1447,7 +1459,12 @@ impl Config {
             rustc
         } else {
             config.download_beta_toolchain();
-            config.out.join(config.build.triple).join("stage0/bin/rustc")
+            config
+                .out
+                .join(config.build.triple)
+                .join("stage0")
+                .join("bin")
+                .join(exe("rustc", config.build))
         };
 
         config.initial_cargo = if let Some(cargo) = cargo {
@@ -1457,7 +1474,12 @@ impl Config {
             cargo
         } else {
             config.download_beta_toolchain();
-            config.out.join(config.build.triple).join("stage0/bin/cargo")
+            config
+                .out
+                .join(config.build.triple)
+                .join("stage0")
+                .join("bin")
+                .join(exe("cargo", config.build))
         };
 
         // NOTE: it's important this comes *after* we set `initial_rustc` just above.
@@ -2043,6 +2065,7 @@ impl Config {
             Subcommand::Bench { .. } => flags.stage.or(bench_stage).unwrap_or(2),
             Subcommand::Dist { .. } => flags.stage.or(dist_stage).unwrap_or(2),
             Subcommand::Install { .. } => flags.stage.or(install_stage).unwrap_or(2),
+            Subcommand::Perf { .. } => flags.stage.unwrap_or(1),
             // These are all bootstrap tools, which don't depend on the compiler.
             // The stage we pass shouldn't matter, but use 0 just in case.
             Subcommand::Clean { .. }
@@ -2080,7 +2103,8 @@ impl Config {
                 | Subcommand::Setup { .. }
                 | Subcommand::Format { .. }
                 | Subcommand::Suggest { .. }
-                | Subcommand::Vendor { .. } => {}
+                | Subcommand::Vendor { .. }
+                | Subcommand::Perf { .. } => {}
             }
         }
 
@@ -2139,7 +2163,7 @@ impl Config {
 
         let mut git = helpers::git(Some(&self.src));
         git.arg("show").arg(format!("{commit}:{}", file.to_str().unwrap()));
-        output(&mut git)
+        output(&mut git.command)
     }
 
     /// Bootstrap embeds a version number into the name of shared libraries it uploads in CI.
@@ -2443,8 +2467,9 @@ impl Config {
         };
 
         // Handle running from a directory other than the top level
-        let top_level =
-            output(helpers::git(Some(&self.src)).args(["rev-parse", "--show-toplevel"]));
+        let top_level = output(
+            &mut helpers::git(Some(&self.src)).args(["rev-parse", "--show-toplevel"]).command,
+        );
         let top_level = top_level.trim_end();
         let compiler = format!("{top_level}/compiler/");
         let library = format!("{top_level}/library/");
@@ -2452,10 +2477,11 @@ impl Config {
         // Look for a version to compare to based on the current commit.
         // Only commits merged by bors will have CI artifacts.
         let merge_base = output(
-            helpers::git(Some(&self.src))
+            &mut helpers::git(Some(&self.src))
                 .arg("rev-list")
                 .arg(format!("--author={}", self.stage0_metadata.config.git_merge_commit_email))
-                .args(["-n1", "--first-parent", "HEAD"]),
+                .args(["-n1", "--first-parent", "HEAD"])
+                .command,
         );
         let commit = merge_base.trim_end();
         if commit.is_empty() {
@@ -2469,6 +2495,7 @@ impl Config {
         // Warn if there were changes to the compiler or standard library since the ancestor commit.
         let has_changes = !t!(helpers::git(Some(&self.src))
             .args(["diff-index", "--quiet", commit, "--", &compiler, &library])
+            .command
             .status())
         .success();
         if has_changes {
@@ -2540,17 +2567,19 @@ impl Config {
         if_unchanged: bool,
     ) -> Option<String> {
         // Handle running from a directory other than the top level
-        let top_level =
-            output(helpers::git(Some(&self.src)).args(["rev-parse", "--show-toplevel"]));
+        let top_level = output(
+            &mut helpers::git(Some(&self.src)).args(["rev-parse", "--show-toplevel"]).command,
+        );
         let top_level = top_level.trim_end();
 
         // Look for a version to compare to based on the current commit.
         // Only commits merged by bors will have CI artifacts.
         let merge_base = output(
-            helpers::git(Some(&self.src))
+            &mut helpers::git(Some(&self.src))
                 .arg("rev-list")
                 .arg(format!("--author={}", self.stage0_metadata.config.git_merge_commit_email))
-                .args(["-n1", "--first-parent", "HEAD"]),
+                .args(["-n1", "--first-parent", "HEAD"])
+                .command,
         );
         let commit = merge_base.trim_end();
         if commit.is_empty() {
@@ -2569,7 +2598,7 @@ impl Config {
             git.arg(format!("{top_level}/{path}"));
         }
 
-        let has_changes = !t!(git.status()).success();
+        let has_changes = !t!(git.command.status()).success();
         if has_changes {
             if if_unchanged {
                 if self.verbose > 0 {
diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs
index 83def0c6df0..aeb608a9ea2 100644
--- a/src/bootstrap/src/core/config/flags.rs
+++ b/src/bootstrap/src/core/config/flags.rs
@@ -469,6 +469,11 @@ Arguments:
         #[arg(long)]
         versioned_dirs: bool,
     },
+    /// Perform profiling and benchmarking of the compiler using the
+    /// `rustc-perf-wrapper` tool.
+    ///
+    /// You need to pass arguments after `--`, e.g.`x perf -- cachegrind`.
+    Perf {},
 }
 
 impl Subcommand {
@@ -490,6 +495,7 @@ impl Subcommand {
             Subcommand::Setup { .. } => Kind::Setup,
             Subcommand::Suggest { .. } => Kind::Suggest,
             Subcommand::Vendor { .. } => Kind::Vendor,
+            Subcommand::Perf { .. } => Kind::Perf,
         }
     }
 
diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs
index 2b11b8c3d4f..a7f4bb0cf14 100644
--- a/src/bootstrap/src/core/download.rs
+++ b/src/bootstrap/src/core/download.rs
@@ -11,6 +11,7 @@ use std::{
 use build_helper::ci::CiEnv;
 use xz2::bufread::XzDecoder;
 
+use crate::utils::exec::{command, BootstrapCommand};
 use crate::utils::helpers::hex_encode;
 use crate::utils::helpers::{check_run, exe, move_file, program_out_of_date};
 use crate::{t, Config};
@@ -56,7 +57,7 @@ impl Config {
     /// Runs a command, printing out nice contextual information if it fails.
     /// Returns false if do not execute at all, otherwise returns its
     /// `status.success()`.
-    pub(crate) fn check_run(&self, cmd: &mut Command) -> bool {
+    pub(crate) fn check_run(&self, cmd: &mut BootstrapCommand) -> bool {
         if self.dry_run() {
             return true;
         }
@@ -173,15 +174,10 @@ impl Config {
         }
 
         let mut patchelf = Command::new(nix_deps_dir.join("bin/patchelf"));
-        let rpath_entries = {
-            // ORIGIN is a relative default, all binary and dynamic libraries we ship
-            // appear to have this (even when `../lib` is redundant).
-            // NOTE: there are only two paths here, delimited by a `:`
-            let mut entries = OsString::from("$ORIGIN/../lib:");
-            entries.push(t!(fs::canonicalize(nix_deps_dir)).join("lib"));
-            entries
-        };
-        patchelf.args(&[OsString::from("--set-rpath"), rpath_entries]);
+        patchelf.args(&[
+            OsString::from("--add-rpath"),
+            OsString::from(t!(fs::canonicalize(nix_deps_dir)).join("lib")),
+        ]);
         if !path_is_dylib(fname) {
             // Finally, set the correct .interp for binaries
             let dynamic_linker_path = nix_deps_dir.join("nix-support/dynamic-linker");
@@ -216,7 +212,7 @@ impl Config {
     fn download_http_with_retries(&self, tempfile: &Path, url: &str, help_on_error: &str) {
         println!("downloading {url}");
         // Try curl. If that fails and we are on windows, fallback to PowerShell.
-        let mut curl = Command::new("curl");
+        let mut curl = command("curl");
         curl.args([
             "-y",
             "30",
diff --git a/src/bootstrap/src/core/metadata.rs b/src/bootstrap/src/core/metadata.rs
index 08a96407a69..b18da844014 100644
--- a/src/bootstrap/src/core/metadata.rs
+++ b/src/bootstrap/src/core/metadata.rs
@@ -1,9 +1,8 @@
 use std::path::PathBuf;
-use std::process::Command;
 
 use serde_derive::Deserialize;
 
-use crate::utils::helpers::output;
+use crate::utils::exec::command;
 use crate::{t, Build, Crate};
 
 /// For more information, see the output of
@@ -67,11 +66,11 @@ pub fn build(build: &mut Build) {
 
 /// Invokes `cargo metadata` to get package metadata of each workspace member.
 ///
-/// Note that `src/tools/cargo` is no longer a workspace member but we still
-/// treat it as one here, by invoking an additional `cargo metadata` command.
-fn workspace_members(build: &Build) -> impl Iterator<Item = Package> {
+/// This is used to resolve specific crate paths in `fn should_run` to compile
+/// particular crate (e.g., `x build sysroot` to build library/sysroot).
+fn workspace_members(build: &Build) -> Vec<Package> {
     let collect_metadata = |manifest_path| {
-        let mut cargo = Command::new(&build.initial_cargo);
+        let mut cargo = command(&build.initial_cargo);
         cargo
             // Will read the libstd Cargo.toml
             // which uses the unstable `public-dependency` feature.
@@ -82,19 +81,11 @@ fn workspace_members(build: &Build) -> impl Iterator<Item = Package> {
             .arg("--no-deps")
             .arg("--manifest-path")
             .arg(build.src.join(manifest_path));
-        let metadata_output = output(&mut cargo);
+        let metadata_output = cargo.capture_stdout().run_always().run(build).stdout();
         let Output { packages, .. } = t!(serde_json::from_str(&metadata_output));
         packages
     };
 
     // Collects `metadata.packages` from all workspaces.
-    let packages = collect_metadata("Cargo.toml");
-    let cargo_packages = collect_metadata("src/tools/cargo/Cargo.toml");
-    let ra_packages = collect_metadata("src/tools/rust-analyzer/Cargo.toml");
-    let bootstrap_packages = collect_metadata("src/bootstrap/Cargo.toml");
-
-    // We only care about the root package from `src/tool/cargo` workspace.
-    let cargo_package = cargo_packages.into_iter().find(|pkg| pkg.name == "cargo").into_iter();
-
-    packages.into_iter().chain(cargo_package).chain(ra_packages).chain(bootstrap_packages)
+    collect_metadata("Cargo.toml")
 }
diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs
index 5a0be2948a1..9995da3a1e5 100644
--- a/src/bootstrap/src/core/sanity.rs
+++ b/src/bootstrap/src/core/sanity.rs
@@ -13,7 +13,6 @@ use std::env;
 use std::ffi::{OsStr, OsString};
 use std::fs;
 use std::path::PathBuf;
-use std::process::Command;
 
 #[cfg(not(feature = "bootstrap-self-test"))]
 use crate::builder::Builder;
@@ -24,7 +23,7 @@ use std::collections::HashSet;
 
 use crate::builder::Kind;
 use crate::core::config::Target;
-use crate::utils::helpers::output;
+use crate::utils::exec::command;
 use crate::Build;
 
 pub struct Finder {
@@ -209,11 +208,12 @@ than building it.
         .or_else(|| cmd_finder.maybe_have("reuse"));
 
     #[cfg(not(feature = "bootstrap-self-test"))]
-    let stage0_supported_target_list: HashSet<String> =
-        output(Command::new(&build.config.initial_rustc).args(["--print", "target-list"]))
-            .lines()
-            .map(|s| s.to_string())
-            .collect();
+    let stage0_supported_target_list: HashSet<String> = crate::utils::helpers::output(
+        &mut command(&build.config.initial_rustc).args(["--print", "target-list"]).command,
+    )
+    .lines()
+    .map(|s| s.to_string())
+    .collect();
 
     // 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.
@@ -352,7 +352,7 @@ than building it.
             // There are three builds of cmake on windows: MSVC, MinGW, and
             // Cygwin. The Cygwin build does not have generators for Visual
             // Studio, so detect that here and error.
-            let out = output(Command::new("cmake").arg("--help"));
+            let out = command("cmake").capture_stdout().arg("--help").run(build).stdout();
             if !out.contains("Visual Studio") {
                 panic!(
                     "
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 449d8c128ec..f16afb29796 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -23,13 +23,13 @@ use std::fmt::Display;
 use std::fs::{self, File};
 use std::io;
 use std::path::{Path, PathBuf};
-use std::process::{Command, Output, Stdio};
+use std::process::{Command, Stdio};
 use std::str;
 use std::sync::OnceLock;
+use std::time::SystemTime;
 
 use build_helper::ci::{gha, CiEnv};
 use build_helper::exit;
-use build_helper::util::fail;
 use filetime::FileTime;
 use sha2::digest::Digest;
 use termcolor::{ColorChoice, StandardStream, WriteColor};
@@ -41,7 +41,7 @@ use crate::core::builder::Kind;
 use crate::core::config::{flags, LldMode};
 use crate::core::config::{DryRun, Target};
 use crate::core::config::{LlvmLibunwind, TargetSelection};
-use crate::utils::exec::{BehaviorOnFailure, BootstrapCommand, OutputMode};
+use crate::utils::exec::{command, BehaviorOnFailure, BootstrapCommand, CommandOutput};
 use crate::utils::helpers::{self, dir_is_empty, exe, libdir, mtime, output, symlink_dir};
 
 mod core;
@@ -74,7 +74,7 @@ const LLVM_TOOLS: &[&str] = &[
 /// LLD file names for all flavors.
 const LLD_FILE_NAMES: &[&str] = &["ld.lld", "ld64.lld", "lld-link", "wasm-ld"];
 
-/// Extra --check-cfg to add when building
+/// Extra `--check-cfg` to add when building the compiler or tools
 /// (Mode restriction, config name, config values (if any))
 #[allow(clippy::type_complexity)] // It's fine for hard-coded list and type is explained above.
 const EXTRA_CHECK_CFGS: &[(Option<Mode>, &str, Option<&[&'static str]>)] = &[
@@ -84,38 +84,9 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &str, Option<&[&'static str]>)] = &[
     (Some(Mode::ToolRustc), "rust_analyzer", None),
     (Some(Mode::ToolStd), "rust_analyzer", None),
     (Some(Mode::Codegen), "parallel_compiler", None),
-    // NOTE: consider updating `check-cfg` entries in `std/Cargo.toml` too.
-    // cfg(bootstrap) remove these once the bootstrap compiler supports
-    // `lints.rust.unexpected_cfgs.check-cfg`
-    (Some(Mode::Std), "stdarch_intel_sde", None),
-    (Some(Mode::Std), "no_fp_fmt_parse", None),
-    (Some(Mode::Std), "no_global_oom_handling", None),
-    (Some(Mode::Std), "no_rc", None),
-    (Some(Mode::Std), "no_sync", None),
-    /* Extra values not defined in the built-in targets yet, but used in std */
-    (Some(Mode::Std), "target_env", Some(&["libnx", "p2"])),
-    (Some(Mode::Std), "target_os", Some(&["visionos"])),
-    (Some(Mode::Std), "target_arch", Some(&["arm64ec", "spirv", "nvptx", "xtensa"])),
-    (Some(Mode::ToolStd), "target_os", Some(&["visionos"])),
-    /* Extra names used by dependencies */
-    // FIXME: Used by serde_json, but we should not be triggering on external dependencies.
-    (Some(Mode::Rustc), "no_btreemap_remove_entry", None),
-    (Some(Mode::ToolRustc), "no_btreemap_remove_entry", None),
-    // FIXME: Used by crossbeam-utils, but we should not be triggering on external dependencies.
-    (Some(Mode::Rustc), "crossbeam_loom", None),
-    (Some(Mode::ToolRustc), "crossbeam_loom", None),
-    // FIXME: Used by proc-macro2, but we should not be triggering on external dependencies.
-    (Some(Mode::Rustc), "span_locations", None),
-    (Some(Mode::ToolRustc), "span_locations", None),
-    // FIXME: Used by rustix, but we should not be triggering on external dependencies.
-    (Some(Mode::Rustc), "rustix_use_libc", None),
-    (Some(Mode::ToolRustc), "rustix_use_libc", None),
-    // FIXME: Used by filetime, but we should not be triggering on external dependencies.
-    (Some(Mode::Rustc), "emulate_second_only_system", None),
-    (Some(Mode::ToolRustc), "emulate_second_only_system", None),
-    // Needed to avoid the need to copy windows.lib into the sysroot.
-    (Some(Mode::Rustc), "windows_raw_dylib", None),
-    (Some(Mode::ToolRustc), "windows_raw_dylib", None),
+    // Any library specific cfgs like `target_os`, `target_arch` should be put in
+    // priority the `[lints.rust.unexpected_cfgs.check-cfg]` table
+    // in the appropriate `library/{std,alloc,core}/Cargo.toml`
 ];
 
 /// A structure representing a Rust compiler.
@@ -469,8 +440,7 @@ impl Build {
 
             // Make sure we update these before gathering metadata so we don't get an error about missing
             // Cargo.toml files.
-            let rust_submodules =
-                ["src/tools/cargo", "src/doc/book", "library/backtrace", "library/stdarch"];
+            let rust_submodules = ["src/doc/book", "library/backtrace", "library/stdarch"];
             for s in rust_submodules {
                 build.update_submodule(Path::new(s));
             }
@@ -523,11 +493,12 @@ impl Build {
         let submodule_git = || helpers::git(Some(&absolute_path));
 
         // Determine commit checked out in submodule.
-        let checked_out_hash = output(submodule_git().args(["rev-parse", "HEAD"]));
+        let checked_out_hash = output(&mut submodule_git().args(["rev-parse", "HEAD"]).command);
         let checked_out_hash = checked_out_hash.trim_end();
         // Determine commit that the submodule *should* have.
-        let recorded =
-            output(helpers::git(Some(&self.src)).args(["ls-tree", "HEAD"]).arg(relative_path));
+        let recorded = output(
+            &mut helpers::git(Some(&self.src)).args(["ls-tree", "HEAD"]).arg(relative_path).command,
+        );
         let actual_hash = recorded
             .split_whitespace()
             .nth(2)
@@ -539,9 +510,10 @@ impl Build {
         }
 
         println!("Updating submodule {}", relative_path.display());
-        self.run(
-            helpers::git(Some(&self.src)).args(["submodule", "-q", "sync"]).arg(relative_path),
-        );
+        helpers::git(Some(&self.src))
+            .args(["submodule", "-q", "sync"])
+            .arg(relative_path)
+            .run(self);
 
         // Try passing `--progress` to start, then run git again without if that fails.
         let update = |progress: bool| {
@@ -550,6 +522,7 @@ impl Build {
             let current_branch = {
                 let output = helpers::git(Some(&self.src))
                     .args(["symbolic-ref", "--short", "HEAD"])
+                    .command
                     .stderr(Stdio::inherit())
                     .output();
                 let output = t!(output);
@@ -575,29 +548,26 @@ impl Build {
             git
         };
         // NOTE: doesn't use `try_run` because this shouldn't print an error if it fails.
-        if !update(true).status().map_or(false, |status| status.success()) {
-            self.run(&mut update(false));
+        if !update(true).command.status().map_or(false, |status| status.success()) {
+            update(false).run(self);
         }
 
         // Save any local changes, but avoid running `git stash pop` if there are none (since it will exit with an error).
         // diff-index reports the modifications through the exit status
-        let has_local_modifications = !self.run_cmd(
-            BootstrapCommand::from(submodule_git().args(["diff-index", "--quiet", "HEAD"]))
-                .allow_failure()
-                .output_mode(match self.is_verbose() {
-                    true => OutputMode::PrintAll,
-                    false => OutputMode::PrintOutput,
-                }),
-        );
+        let has_local_modifications = submodule_git()
+            .allow_failure()
+            .args(["diff-index", "--quiet", "HEAD"])
+            .run(self)
+            .is_failure();
         if has_local_modifications {
-            self.run(submodule_git().args(["stash", "push"]));
+            submodule_git().args(["stash", "push"]).run(self);
         }
 
-        self.run(submodule_git().args(["reset", "-q", "--hard"]));
-        self.run(submodule_git().args(["clean", "-qdfx"]));
+        submodule_git().args(["reset", "-q", "--hard"]).run(self);
+        submodule_git().args(["clean", "-qdfx"]).run(self);
 
         if has_local_modifications {
-            self.run(submodule_git().args(["stash", "pop"]));
+            submodule_git().args(["stash", "pop"]).run(self);
         }
     }
 
@@ -608,12 +578,13 @@ impl Build {
         if !self.config.submodules(self.rust_info()) {
             return;
         }
-        let output = output(
-            helpers::git(Some(&self.src))
-                .args(["config", "--file"])
-                .arg(self.config.src.join(".gitmodules"))
-                .args(["--get-regexp", "path"]),
-        );
+        let output = helpers::git(Some(&self.src))
+            .capture()
+            .args(["config", "--file"])
+            .arg(self.config.src.join(".gitmodules"))
+            .args(["--get-regexp", "path"])
+            .run(self)
+            .stdout();
         for line in output.lines() {
             // Look for `submodule.$name.path = $path`
             // Sample output: `submodule.src/rust-installer.path src/tools/rust-installer`
@@ -659,6 +630,9 @@ impl Build {
             Subcommand::Suggest { run } => {
                 return core::build_steps::suggest::suggest(&builder::Builder::new(self), *run);
             }
+            Subcommand::Perf { .. } => {
+                return core::build_steps::perf::perf(&builder::Builder::new(self));
+            }
             _ => (),
         }
 
@@ -887,14 +861,14 @@ impl Build {
         if let Some(s) = target_config.and_then(|c| c.llvm_filecheck.as_ref()) {
             s.to_path_buf()
         } else if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
-            let llvm_bindir = output(Command::new(s).arg("--bindir"));
+            let llvm_bindir = command(s).capture_stdout().arg("--bindir").run(self).stdout();
             let filecheck = Path::new(llvm_bindir.trim()).join(exe("FileCheck", target));
             if filecheck.exists() {
                 filecheck
             } else {
                 // On Fedora the system LLVM installs FileCheck in the
                 // llvm subdirectory of the libdir.
-                let llvm_libdir = output(Command::new(s).arg("--libdir"));
+                let llvm_libdir = command(s).capture_stdout().arg("--libdir").run(self).stdout();
                 let lib_filecheck =
                     Path::new(llvm_libdir.trim()).join("llvm").join(exe("FileCheck", target));
                 if lib_filecheck.exists() {
@@ -937,7 +911,7 @@ impl Build {
     }
 
     /// Adds the `RUST_TEST_THREADS` env var if necessary
-    fn add_rust_test_threads(&self, cmd: &mut Command) {
+    fn add_rust_test_threads(&self, cmd: &mut BootstrapCommand) {
         if env::var_os("RUST_TEST_THREADS").is_none() {
             cmd.env("RUST_TEST_THREADS", self.jobs().to_string());
         }
@@ -958,113 +932,83 @@ impl Build {
         })
     }
 
-    /// Runs a command, printing out nice contextual information if it fails.
-    fn run(&self, cmd: &mut Command) {
-        self.run_cmd(BootstrapCommand::from(cmd).fail_fast().output_mode(
-            match self.is_verbose() {
-                true => OutputMode::PrintAll,
-                false => OutputMode::PrintOutput,
-            },
-        ));
-    }
-
-    /// Runs a command, printing out contextual info if it fails, and delaying errors until the build finishes.
-    pub(crate) fn run_delaying_failure(&self, cmd: &mut Command) -> bool {
-        self.run_cmd(BootstrapCommand::from(cmd).delay_failure().output_mode(
-            match self.is_verbose() {
-                true => OutputMode::PrintAll,
-                false => OutputMode::PrintOutput,
-            },
-        ))
-    }
-
-    /// Runs a command, printing out nice contextual information if it fails.
-    fn run_quiet(&self, cmd: &mut Command) {
-        self.run_cmd(
-            BootstrapCommand::from(cmd).fail_fast().output_mode(OutputMode::SuppressOnSuccess),
-        );
-    }
-
-    /// Runs a command, printing out nice contextual information if it fails.
-    /// Exits if the command failed to execute at all, otherwise returns its
-    /// `status.success()`.
-    fn run_quiet_delaying_failure(&self, cmd: &mut Command) -> bool {
-        self.run_cmd(
-            BootstrapCommand::from(cmd).delay_failure().output_mode(OutputMode::SuppressOnSuccess),
-        )
-    }
-
-    /// A centralized function for running commands that do not return output.
-    pub(crate) fn run_cmd<'a, C: Into<BootstrapCommand<'a>>>(&self, cmd: C) -> bool {
-        if self.config.dry_run() {
-            return true;
+    /// Execute a command and return its output.
+    /// This method should be used for all command executions in bootstrap.
+    fn run(&self, command: &mut BootstrapCommand) -> CommandOutput {
+        if self.config.dry_run() && !command.run_always {
+            return CommandOutput::default();
         }
 
-        let command = cmd.into();
         self.verbose(|| println!("running: {command:?}"));
 
-        let (output, print_error) = match command.output_mode {
-            mode @ (OutputMode::PrintAll | OutputMode::PrintOutput) => (
-                command.command.status().map(|status| Output {
-                    status,
-                    stdout: Vec::new(),
-                    stderr: Vec::new(),
-                }),
-                matches!(mode, OutputMode::PrintAll),
-            ),
-            OutputMode::SuppressOnSuccess => (command.command.output(), true),
-        };
+        command.command.stdout(command.stdout.stdio());
+        command.command.stderr(command.stderr.stdio());
 
-        let output = match output {
-            Ok(output) => output,
-            Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", command, e)),
-        };
-        let result = if !output.status.success() {
-            if print_error {
-                println!(
-                    "\n\nCommand did not execute successfully.\
-                    \nExpected success, got: {}",
+        let output = command.command.output();
+
+        use std::fmt::Write;
+
+        let mut message = String::new();
+        let output: CommandOutput = match output {
+            // Command has succeeded
+            Ok(output) if output.status.success() => output.into(),
+            // Command has started, but then it failed
+            Ok(output) => {
+                writeln!(
+                    message,
+                    "\n\nCommand {command:?} did not execute successfully.\
+            \nExpected success, got: {}",
                     output.status,
-                );
+                )
+                .unwrap();
 
-                if !self.is_verbose() {
-                    println!("Add `-v` to see more details.\n");
-                }
+                let output: CommandOutput = output.into();
 
-                self.verbose(|| {
-                    println!(
-                        "\nSTDOUT ----\n{}\n\
-                        STDERR ----\n{}\n",
-                        String::from_utf8_lossy(&output.stdout),
-                        String::from_utf8_lossy(&output.stderr)
-                    )
-                });
+                // If the output mode is OutputMode::Capture, we can now print the output.
+                // If it is OutputMode::Print, then the output has already been printed to
+                // stdout/stderr, and we thus don't have anything captured to print anyway.
+                if command.stdout.captures() {
+                    writeln!(message, "\nSTDOUT ----\n{}", output.stdout().trim()).unwrap();
+                }
+                if command.stderr.captures() {
+                    writeln!(message, "\nSTDERR ----\n{}", output.stderr().trim()).unwrap();
+                }
+                output
+            }
+            // The command did not even start
+            Err(e) => {
+                writeln!(
+                    message,
+                    "\n\nCommand {command:?} did not execute successfully.\
+            \nIt was not possible to execute the command: {e:?}"
+                )
+                .unwrap();
+                CommandOutput::did_not_start()
             }
-            Err(())
-        } else {
-            Ok(())
         };
-
-        match result {
-            Ok(_) => true,
-            Err(_) => {
-                match command.failure_behavior {
-                    BehaviorOnFailure::DelayFail => {
-                        if self.fail_fast {
-                            exit!(1);
-                        }
-
-                        let mut failures = self.delayed_failures.borrow_mut();
-                        failures.push(format!("{command:?}"));
-                    }
-                    BehaviorOnFailure::Exit => {
+        if !output.is_success() {
+            match command.failure_behavior {
+                BehaviorOnFailure::DelayFail => {
+                    if self.fail_fast {
+                        println!("{message}");
                         exit!(1);
                     }
-                    BehaviorOnFailure::Ignore => {}
+
+                    let mut failures = self.delayed_failures.borrow_mut();
+                    failures.push(message);
+                }
+                BehaviorOnFailure::Exit => {
+                    println!("{message}");
+                    exit!(1);
+                }
+                BehaviorOnFailure::Ignore => {
+                    // If failures are allowed, either the error has been printed already
+                    // (OutputMode::Print) or the user used a capture output mode and wants to
+                    // handle the error output on their own.
                 }
-                false
             }
         }
+        output
     }
 
     /// Check if verbosity is greater than the `level`
@@ -1550,14 +1494,17 @@ impl Build {
             // Figure out how many merge commits happened since we branched off master.
             // That's our beta number!
             // (Note that we use a `..` range, not the `...` symmetric difference.)
-            output(
-                helpers::git(Some(&self.src)).arg("rev-list").arg("--count").arg("--merges").arg(
-                    format!(
-                        "refs/remotes/origin/{}..HEAD",
-                        self.config.stage0_metadata.config.nightly_branch
-                    ),
-                ),
-            )
+            helpers::git(Some(&self.src))
+                .capture()
+                .arg("rev-list")
+                .arg("--count")
+                .arg("--merges")
+                .arg(format!(
+                    "refs/remotes/origin/{}..HEAD",
+                    self.config.stage0_metadata.config.nightly_branch
+                ))
+                .run(self)
+                .stdout()
         });
         let n = count.trim().parse().unwrap();
         self.prerelease_version.set(Some(n));
@@ -1718,7 +1665,14 @@ impl Build {
         if src == dst {
             return;
         }
-        let _ = fs::remove_file(dst);
+        if let Err(e) = fs::remove_file(dst) {
+            if cfg!(windows) && e.kind() != io::ErrorKind::NotFound {
+                // workaround for https://github.com/rust-lang/rust/issues/127126
+                // if removing the file fails, attempt to rename it instead.
+                let now = t!(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH));
+                let _ = fs::rename(dst, format!("{}-{}", dst.display(), now.as_nanos()));
+            }
+        }
         let metadata = t!(src.symlink_metadata(), format!("src = {}", src.display()));
         let mut src = src.to_path_buf();
         if metadata.file_type().is_symlink() {
@@ -1977,6 +1931,7 @@ fn envify(s: &str) -> String {
 pub fn generate_smart_stamp_hash(dir: &Path, additional_input: &str) -> String {
     let diff = helpers::git(Some(dir))
         .arg("diff")
+        .command
         .output()
         .map(|o| String::from_utf8(o.stdout).unwrap_or_default())
         .unwrap_or_default();
@@ -1986,6 +1941,7 @@ pub fn generate_smart_stamp_hash(dir: &Path, additional_input: &str) -> String {
         .arg("--porcelain")
         .arg("-z")
         .arg("--untracked-files=normal")
+        .command
         .output()
         .map(|o| String::from_utf8(o.stdout).unwrap_or_default())
         .unwrap_or_default();
diff --git a/src/bootstrap/src/utils/bin_helpers.rs b/src/bootstrap/src/utils/bin_helpers.rs
deleted file mode 100644
index 5fbbe0bde0e..00000000000
--- a/src/bootstrap/src/utils/bin_helpers.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-//! This file is meant to be included directly from bootstrap shims to avoid a
-//! dependency on the bootstrap library. This reduces the binary size and
-//! improves compilation time by reducing the linking time.
-
-use std::env;
-use std::fs::OpenOptions;
-use std::io::Write;
-use std::process::Command;
-use std::str::FromStr;
-
-/// Parses the value of the "RUSTC_VERBOSE" environment variable and returns it as a `usize`.
-/// If it was not defined, returns 0 by default.
-///
-/// Panics if "RUSTC_VERBOSE" is defined with the value that is not an unsigned integer.
-pub(crate) fn parse_rustc_verbose() -> usize {
-    match env::var("RUSTC_VERBOSE") {
-        Ok(s) => usize::from_str(&s).expect("RUSTC_VERBOSE should be an integer"),
-        Err(_) => 0,
-    }
-}
-
-/// Parses the value of the "RUSTC_STAGE" environment variable and returns it as a `String`.
-///
-/// If "RUSTC_STAGE" was not set, the program will be terminated with 101.
-pub(crate) fn parse_rustc_stage() -> String {
-    env::var("RUSTC_STAGE").unwrap_or_else(|_| {
-        // Don't panic here; it's reasonable to try and run these shims directly. Give a helpful error instead.
-        eprintln!("rustc shim: FATAL: RUSTC_STAGE was not set");
-        eprintln!("rustc shim: NOTE: use `x.py build -vvv` to see all environment variables set by bootstrap");
-        std::process::exit(101);
-    })
-}
-
-/// Writes the command invocation to a file if `DUMP_BOOTSTRAP_SHIMS` is set during bootstrap.
-///
-/// Before writing it, replaces user-specific values to create generic dumps for cross-environment
-/// comparisons.
-pub(crate) fn maybe_dump(dump_name: String, cmd: &Command) {
-    if let Ok(dump_dir) = env::var("DUMP_BOOTSTRAP_SHIMS") {
-        let dump_file = format!("{dump_dir}/{dump_name}");
-
-        let mut file = OpenOptions::new().create(true).append(true).open(dump_file).unwrap();
-
-        let cmd_dump = format!("{:?}\n", cmd);
-        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}");
-
-        file.write_all(cmd_dump.as_bytes()).expect("Unable to write file");
-    }
-}
diff --git a/src/bootstrap/src/utils/cache.rs b/src/bootstrap/src/utils/cache.rs
index e18dcbb47be..d60b54dc703 100644
--- a/src/bootstrap/src/utils/cache.rs
+++ b/src/bootstrap/src/utils/cache.rs
@@ -9,10 +9,7 @@ use std::marker::PhantomData;
 use std::mem;
 use std::ops::Deref;
 use std::path::PathBuf;
-use std::sync::Mutex;
-
-// FIXME: replace with std::lazy after it gets stabilized and reaches beta
-use once_cell::sync::Lazy;
+use std::sync::{LazyLock, Mutex};
 
 use crate::core::builder::Step;
 
@@ -196,7 +193,7 @@ impl Interner {
     }
 }
 
-pub static INTERNER: Lazy<Interner> = Lazy::new(Interner::default);
+pub static INTERNER: LazyLock<Interner> = LazyLock::new(Interner::default);
 
 /// This is essentially a `HashMap` which allows storing any type in its input and
 /// any type in its output. It is a write-once cache; values are never evicted,
diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs
index 540b8671333..d6fa7fc0bbe 100644
--- a/src/bootstrap/src/utils/cc_detect.rs
+++ b/src/bootstrap/src/utils/cc_detect.rs
@@ -23,11 +23,10 @@
 
 use std::collections::HashSet;
 use std::path::{Path, PathBuf};
-use std::process::Command;
 use std::{env, iter};
 
 use crate::core::config::TargetSelection;
-use crate::utils::helpers::output;
+use crate::utils::exec::{command, BootstrapCommand};
 use crate::{Build, CLang, GitRepo};
 
 // The `cc` crate doesn't provide a way to obtain a path to the detected archiver,
@@ -183,14 +182,15 @@ fn default_compiler(
                 return None;
             }
 
-            let output = output(c.to_command().arg("--version"));
+            let cmd = BootstrapCommand::from(c.to_command());
+            let output = cmd.capture_stdout().arg("--version").run(build).stdout();
             let i = output.find(" 4.")?;
             match output[i + 3..].chars().next().unwrap() {
                 '0'..='6' => {}
                 _ => return None,
             }
             let alternative = format!("e{gnu_compiler}");
-            if Command::new(&alternative).output().is_ok() {
+            if command(&alternative).capture().run(build).is_success() {
                 Some(PathBuf::from(alternative))
             } else {
                 None
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index bfe3622e40d..ccab25e55a9 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -195,4 +195,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Warning,
         summary: "Removed `dist.missing-tools` configuration as it was deprecated long time ago.",
     },
+    ChangeInfo {
+        change_id: 126701,
+        severity: ChangeSeverity::Warning,
+        summary: "`llvm.lld` is enabled by default for the dist profile. If set to false, `lld` will not be included in the dist build.",
+    },
 ];
diff --git a/src/bootstrap/src/utils/channel.rs b/src/bootstrap/src/utils/channel.rs
index ce82c52f049..2ca86bdb0ed 100644
--- a/src/bootstrap/src/utils/channel.rs
+++ b/src/bootstrap/src/utils/channel.rs
@@ -45,7 +45,7 @@ impl GitInfo {
         }
 
         // Make sure git commands work
-        match helpers::git(Some(dir)).arg("rev-parse").output() {
+        match helpers::git(Some(dir)).arg("rev-parse").command.output() {
             Ok(ref out) if out.status.success() => {}
             _ => return GitInfo::Absent,
         }
@@ -58,15 +58,17 @@ impl GitInfo {
 
         // Ok, let's scrape some info
         let ver_date = output(
-            helpers::git(Some(dir))
+            &mut helpers::git(Some(dir))
                 .arg("log")
                 .arg("-1")
                 .arg("--date=short")
-                .arg("--pretty=format:%cd"),
+                .arg("--pretty=format:%cd")
+                .command,
+        );
+        let ver_hash = output(&mut helpers::git(Some(dir)).arg("rev-parse").arg("HEAD").command);
+        let short_ver_hash = output(
+            &mut helpers::git(Some(dir)).arg("rev-parse").arg("--short=9").arg("HEAD").command,
         );
-        let ver_hash = output(helpers::git(Some(dir)).arg("rev-parse").arg("HEAD"));
-        let short_ver_hash =
-            output(helpers::git(Some(dir)).arg("rev-parse").arg("--short=9").arg("HEAD"));
         GitInfo::Present(Some(Info {
             commit_date: ver_date.trim().to_string(),
             sha: ver_hash.trim().to_string(),
diff --git a/src/bootstrap/src/utils/dylib.rs b/src/bootstrap/src/utils/dylib.rs
deleted file mode 100644
index 90bcff59a64..00000000000
--- a/src/bootstrap/src/utils/dylib.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-//! Various utilities for working with dylib paths.
-
-/// 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") {
-        "PATH"
-    } else if cfg!(target_vendor = "apple") {
-        "DYLD_LIBRARY_PATH"
-    } else if cfg!(target_os = "haiku") {
-        "LIBRARY_PATH"
-    } else if cfg!(target_os = "aix") {
-        "LIBPATH"
-    } else {
-        "LD_LIBRARY_PATH"
-    }
-}
-
-/// Parses the `dylib_path_var()` environment variable, returning a list of
-/// paths that are members of this lookup path.
-pub fn dylib_path() -> Vec<std::path::PathBuf> {
-    let var = match std::env::var_os(dylib_path_var()) {
-        Some(v) => v,
-        None => return vec![],
-    };
-    std::env::split_paths(&var).collect()
-}
-
-/// Given an executable called `name`, return the filename for the
-/// executable for a particular target.
-#[allow(dead_code)]
-pub fn exe(name: &str, target: &str) -> String {
-    if target.contains("windows") {
-        format!("{name}.exe")
-    } else if target.contains("uefi") {
-        format!("{name}.efi")
-    } else {
-        name.to_string()
-    }
-}
diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs
index 0aede2022ba..ba963f52dc2 100644
--- a/src/bootstrap/src/utils/exec.rs
+++ b/src/bootstrap/src/utils/exec.rs
@@ -1,4 +1,7 @@
-use std::process::Command;
+use crate::Build;
+use std::ffi::OsStr;
+use std::path::Path;
+use std::process::{Command, CommandArgs, CommandEnvs, ExitStatus, Output, Stdio};
 
 /// What should be done when the command fails.
 #[derive(Debug, Copy, Clone)]
@@ -11,50 +14,233 @@ pub enum BehaviorOnFailure {
     Ignore,
 }
 
-/// How should the output of the command be handled.
+/// How should the output of a specific stream of the command (stdout/stderr) be handled
+/// (whether it should be captured or printed).
 #[derive(Debug, Copy, Clone)]
 pub enum OutputMode {
-    /// Print both the output (by inheriting stdout/stderr) and also the command itself, if it
-    /// fails.
-    PrintAll,
-    /// Print the output (by inheriting stdout/stderr).
-    PrintOutput,
-    /// Suppress the output if the command succeeds, otherwise print the output.
-    SuppressOnSuccess,
+    /// Prints the stream by inheriting it from the bootstrap process.
+    Print,
+    /// Captures the stream into memory.
+    Capture,
+}
+
+impl OutputMode {
+    pub fn captures(&self) -> bool {
+        match self {
+            OutputMode::Print => false,
+            OutputMode::Capture => true,
+        }
+    }
+
+    pub fn stdio(&self) -> Stdio {
+        match self {
+            OutputMode::Print => Stdio::inherit(),
+            OutputMode::Capture => Stdio::piped(),
+        }
+    }
 }
 
 /// Wrapper around `std::process::Command`.
+///
+/// By default, the command will exit bootstrap if it fails.
+/// If you want to allow failures, use [allow_failure].
+/// If you want to delay failures until the end of bootstrap, use [delay_failure].
+///
+/// By default, the command will print its stdout/stderr to stdout/stderr of bootstrap ([OutputMode::Print]).
+/// If you want to handle the output programmatically, use [BootstrapCommand::capture].
+///
+/// Bootstrap will print a debug log to stdout if the command fails and failure is not allowed.
+///
+/// [allow_failure]: BootstrapCommand::allow_failure
+/// [delay_failure]: BootstrapCommand::delay_failure
 #[derive(Debug)]
-pub struct BootstrapCommand<'a> {
-    pub command: &'a mut Command,
+pub struct BootstrapCommand {
+    pub command: Command,
     pub failure_behavior: BehaviorOnFailure,
-    pub output_mode: OutputMode,
+    pub stdout: OutputMode,
+    pub stderr: OutputMode,
+    // Run the command even during dry run
+    pub run_always: bool,
 }
 
-impl<'a> BootstrapCommand<'a> {
+impl BootstrapCommand {
+    pub fn new<S: AsRef<OsStr>>(program: S) -> Self {
+        Command::new(program).into()
+    }
+
+    pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Self {
+        self.command.arg(arg.as_ref());
+        self
+    }
+
+    pub fn args<I, S>(&mut self, args: I) -> &mut Self
+    where
+        I: IntoIterator<Item = S>,
+        S: AsRef<OsStr>,
+    {
+        self.command.args(args);
+        self
+    }
+
+    pub fn env<K, V>(&mut self, key: K, val: V) -> &mut Self
+    where
+        K: AsRef<OsStr>,
+        V: AsRef<OsStr>,
+    {
+        self.command.env(key, val);
+        self
+    }
+
+    pub fn get_envs(&self) -> CommandEnvs<'_> {
+        self.command.get_envs()
+    }
+
+    pub fn get_args(&self) -> CommandArgs<'_> {
+        self.command.get_args()
+    }
+
+    pub fn env_remove<K: AsRef<OsStr>>(&mut self, key: K) -> &mut Self {
+        self.command.env_remove(key);
+        self
+    }
+
+    pub fn current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut Self {
+        self.command.current_dir(dir);
+        self
+    }
+
+    #[must_use]
     pub fn delay_failure(self) -> Self {
         Self { failure_behavior: BehaviorOnFailure::DelayFail, ..self }
     }
 
+    #[must_use]
     pub fn fail_fast(self) -> Self {
         Self { failure_behavior: BehaviorOnFailure::Exit, ..self }
     }
 
+    #[must_use]
     pub fn allow_failure(self) -> Self {
         Self { failure_behavior: BehaviorOnFailure::Ignore, ..self }
     }
 
-    pub fn output_mode(self, output_mode: OutputMode) -> Self {
-        Self { output_mode, ..self }
+    pub fn run_always(&mut self) -> &mut Self {
+        self.run_always = true;
+        self
+    }
+
+    /// Capture all output of the command, do not print it.
+    #[must_use]
+    pub fn capture(self) -> Self {
+        Self { stdout: OutputMode::Capture, stderr: OutputMode::Capture, ..self }
+    }
+
+    /// Capture stdout of the command, do not print it.
+    #[must_use]
+    pub fn capture_stdout(self) -> Self {
+        Self { stdout: OutputMode::Capture, ..self }
+    }
+
+    /// Run the command, returning its output.
+    pub fn run(&mut self, builder: &Build) -> CommandOutput {
+        builder.run(self)
     }
 }
 
-impl<'a> From<&'a mut Command> for BootstrapCommand<'a> {
-    fn from(command: &'a mut Command) -> Self {
+impl From<Command> for BootstrapCommand {
+    fn from(command: Command) -> Self {
         Self {
             command,
             failure_behavior: BehaviorOnFailure::Exit,
-            output_mode: OutputMode::PrintAll,
+            stdout: OutputMode::Print,
+            stderr: OutputMode::Print,
+            run_always: false,
+        }
+    }
+}
+
+/// Represents the current status of `BootstrapCommand`.
+enum CommandStatus {
+    /// The command has started and finished with some status.
+    Finished(ExitStatus),
+    /// It was not even possible to start the command.
+    DidNotStart,
+}
+
+/// Create a new BootstrapCommand. This is a helper function to make command creation
+/// shorter than `BootstrapCommand::new`.
+#[must_use]
+pub fn command<S: AsRef<OsStr>>(program: S) -> BootstrapCommand {
+    BootstrapCommand::new(program)
+}
+
+/// Represents the output of an executed process.
+#[allow(unused)]
+pub struct CommandOutput {
+    status: CommandStatus,
+    stdout: Vec<u8>,
+    stderr: Vec<u8>,
+}
+
+impl CommandOutput {
+    #[must_use]
+    pub fn did_not_start() -> Self {
+        Self { status: CommandStatus::DidNotStart, stdout: vec![], stderr: vec![] }
+    }
+
+    #[must_use]
+    pub fn is_success(&self) -> bool {
+        match self.status {
+            CommandStatus::Finished(status) => status.success(),
+            CommandStatus::DidNotStart => false,
+        }
+    }
+
+    #[must_use]
+    pub fn is_failure(&self) -> bool {
+        !self.is_success()
+    }
+
+    #[must_use]
+    pub fn status(&self) -> Option<ExitStatus> {
+        match self.status {
+            CommandStatus::Finished(status) => Some(status),
+            CommandStatus::DidNotStart => None,
+        }
+    }
+
+    #[must_use]
+    pub fn stdout(&self) -> String {
+        String::from_utf8(self.stdout.clone()).expect("Cannot parse process stdout as UTF-8")
+    }
+
+    #[must_use]
+    pub fn stdout_if_ok(&self) -> Option<String> {
+        if self.is_success() { Some(self.stdout()) } else { None }
+    }
+
+    #[must_use]
+    pub fn stderr(&self) -> String {
+        String::from_utf8(self.stderr.clone()).expect("Cannot parse process stderr as UTF-8")
+    }
+}
+
+impl Default for CommandOutput {
+    fn default() -> Self {
+        Self {
+            status: CommandStatus::Finished(ExitStatus::default()),
+            stdout: vec![],
+            stderr: vec![],
+        }
+    }
+}
+
+impl From<Output> for CommandOutput {
+    fn from(output: Output) -> Self {
+        Self {
+            status: CommandStatus::Finished(output.status),
+            stdout: output.stdout,
+            stderr: output.stderr,
         }
     }
 }
diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs
index 4b6dc45b436..5dd3ba96786 100644
--- a/src/bootstrap/src/utils/helpers.rs
+++ b/src/bootstrap/src/utils/helpers.rs
@@ -18,7 +18,7 @@ use crate::core::builder::Builder;
 use crate::core::config::{Config, TargetSelection};
 use crate::LldMode;
 
-pub use crate::utils::dylib::{dylib_path, dylib_path_var};
+pub use crate::utils::shared_helpers::{dylib_path, dylib_path_var};
 
 #[cfg(test)]
 mod tests;
@@ -47,10 +47,11 @@ macro_rules! t {
         }
     };
 }
+use crate::utils::exec::{command, BootstrapCommand};
 pub use t;
 
 pub fn exe(name: &str, target: TargetSelection) -> String {
-    crate::utils::dylib::exe(name, &target.triple)
+    crate::utils::shared_helpers::exe(name, &target.triple)
 }
 
 /// Returns `true` if the file name given looks like a dynamic library.
@@ -72,7 +73,7 @@ pub fn libdir(target: TargetSelection) -> &'static str {
 
 /// Adds a list of lookup paths to `cmd`'s dynamic library lookup path.
 /// If the dylib_path_var is already set for this cmd, the old value will be overwritten!
-pub fn add_dylib_path(path: Vec<PathBuf>, cmd: &mut Command) {
+pub fn add_dylib_path(path: Vec<PathBuf>, cmd: &mut BootstrapCommand) {
     let mut list = dylib_path();
     for path in path {
         list.insert(0, path);
@@ -81,7 +82,7 @@ pub fn add_dylib_path(path: Vec<PathBuf>, cmd: &mut Command) {
 }
 
 /// Adds a list of lookup paths to `cmd`'s link library lookup path.
-pub fn add_link_lib_path(path: Vec<PathBuf>, cmd: &mut Command) {
+pub fn add_link_lib_path(path: Vec<PathBuf>, cmd: &mut BootstrapCommand) {
     let mut list = link_lib_path();
     for path in path {
         list.insert(0, path);
@@ -135,7 +136,7 @@ pub fn symlink_dir(config: &Config, original: &Path, link: &Path) -> io::Result<
     if config.dry_run() {
         return Ok(());
     }
-    let _ = fs::remove_dir(link);
+    let _ = fs::remove_dir_all(link);
     return symlink_dir_inner(original, link);
 
     #[cfg(not(windows))]
@@ -241,8 +242,9 @@ pub fn is_valid_test_suite_arg<'a, P: AsRef<Path>>(
     }
 }
 
-pub fn check_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool {
-    let status = match cmd.status() {
+// FIXME: get rid of this function
+pub fn check_run(cmd: &mut BootstrapCommand, print_cmd_on_fail: bool) -> bool {
+    let status = match cmd.command.status() {
         Ok(status) => status,
         Err(e) => {
             println!("failed to execute command: {cmd:?}\nERROR: {e}");
@@ -358,7 +360,7 @@ pub fn get_clang_cl_resource_dir(clang_cl_path: &str) -> PathBuf {
 /// Returns a flag that configures LLD to use only a single thread.
 /// If we use an external LLD, we need to find out which version is it to know which flag should we
 /// pass to it (LLD older than version 10 had a different flag).
-fn lld_flag_no_threads(lld_mode: LldMode, is_windows: bool) -> &'static str {
+fn lld_flag_no_threads(builder: &Builder<'_>, lld_mode: LldMode, is_windows: bool) -> &'static str {
     static LLD_NO_THREADS: OnceLock<(&'static str, &'static str)> = OnceLock::new();
 
     let new_flags = ("/threads:1", "--threads=1");
@@ -367,7 +369,9 @@ fn lld_flag_no_threads(lld_mode: LldMode, is_windows: bool) -> &'static str {
     let (windows_flag, other_flag) = LLD_NO_THREADS.get_or_init(|| {
         let newer_version = match lld_mode {
             LldMode::External => {
-                let out = output(Command::new("lld").arg("-flavor").arg("ld").arg("--version"));
+                let mut cmd = command("lld").capture_stdout();
+                cmd.arg("-flavor").arg("ld").arg("--version");
+                let out = cmd.run(builder).stdout();
                 match (out.find(char::is_numeric), out.find('.')) {
                     (Some(b), Some(e)) => out.as_str()[b..e].parse::<i32>().ok().unwrap_or(14) > 10,
                     _ => true,
@@ -429,7 +433,7 @@ pub fn linker_flags(
         if matches!(lld_threads, LldThreads::No) {
             args.push(format!(
                 "-Clink-arg=-Wl,{}",
-                lld_flag_no_threads(builder.config.lld_mode, target.is_windows())
+                lld_flag_no_threads(builder, builder.config.lld_mode, target.is_windows())
             ));
         }
     }
@@ -437,7 +441,7 @@ pub fn linker_flags(
 }
 
 pub fn add_rustdoc_cargo_linker_args(
-    cmd: &mut Command,
+    cmd: &mut BootstrapCommand,
     builder: &Builder<'_>,
     target: TargetSelection,
     lld_threads: LldThreads,
@@ -490,14 +494,15 @@ pub fn check_cfg_arg(name: &str, values: Option<&[&str]>) -> String {
     format!("--check-cfg=cfg({name}{next})")
 }
 
-/// Prepares `Command` that runs git inside the source directory if given.
+/// Prepares `BootstrapCommand` that runs git inside the source directory if given.
 ///
 /// Whenever a git invocation is needed, this function should be preferred over
-/// manually building a git `Command`. This approach allows us to manage bootstrap-specific
-/// needs/hacks from a single source, rather than applying them on next to every `Command::new("git")`,
-/// which is painful to ensure that the required change is applied on each one of them correctly.
-pub fn git(source_dir: Option<&Path>) -> Command {
-    let mut git = Command::new("git");
+/// manually building a git `BootstrapCommand`. This approach allows us to manage
+/// bootstrap-specific needs/hacks from a single source, rather than applying them on next to every
+/// git command creation, which is painful to ensure that the required change is applied
+/// on each one of them correctly.
+pub fn git(source_dir: Option<&Path>) -> BootstrapCommand {
+    let mut git = command("git");
 
     if let Some(source_dir) = source_dir {
         git.current_dir(source_dir);
diff --git a/src/bootstrap/src/utils/mod.rs b/src/bootstrap/src/utils/mod.rs
index cb535f0e163..53b41f15780 100644
--- a/src/bootstrap/src/utils/mod.rs
+++ b/src/bootstrap/src/utils/mod.rs
@@ -6,11 +6,11 @@ pub(crate) mod cache;
 pub(crate) mod cc_detect;
 pub(crate) mod change_tracker;
 pub(crate) mod channel;
-pub(crate) mod dylib;
 pub(crate) mod exec;
 pub(crate) mod helpers;
 pub(crate) mod job;
 #[cfg(feature = "build-metrics")]
 pub(crate) mod metrics;
 pub(crate) mod render_tests;
+pub(crate) mod shared_helpers;
 pub(crate) mod tarball;
diff --git a/src/bootstrap/src/utils/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs
index 5c9918bce32..2e99bc68a8b 100644
--- a/src/bootstrap/src/utils/render_tests.rs
+++ b/src/bootstrap/src/utils/render_tests.rs
@@ -7,14 +7,18 @@
 //! to reimplement all the rendering logic in this module because of that.
 
 use crate::core::builder::Builder;
+use crate::utils::exec::BootstrapCommand;
 use std::io::{BufRead, BufReader, Read, Write};
-use std::process::{ChildStdout, Command, Stdio};
+use std::process::{ChildStdout, Stdio};
 use std::time::Duration;
 use termcolor::{Color, ColorSpec, WriteColor};
 
 const TERSE_TESTS_PER_LINE: usize = 88;
 
-pub(crate) fn add_flags_and_try_run_tests(builder: &Builder<'_>, cmd: &mut Command) -> bool {
+pub(crate) fn add_flags_and_try_run_tests(
+    builder: &Builder<'_>,
+    cmd: &mut BootstrapCommand,
+) -> bool {
     if !cmd.get_args().any(|arg| arg == "--") {
         cmd.arg("--");
     }
@@ -23,7 +27,11 @@ pub(crate) fn add_flags_and_try_run_tests(builder: &Builder<'_>, cmd: &mut Comma
     try_run_tests(builder, cmd, false)
 }
 
-pub(crate) fn try_run_tests(builder: &Builder<'_>, cmd: &mut Command, stream: bool) -> bool {
+pub(crate) fn try_run_tests(
+    builder: &Builder<'_>,
+    cmd: &mut BootstrapCommand,
+    stream: bool,
+) -> bool {
     if builder.config.dry_run() {
         return true;
     }
@@ -41,7 +49,8 @@ pub(crate) fn try_run_tests(builder: &Builder<'_>, cmd: &mut Command, stream: bo
     }
 }
 
-fn run_tests(builder: &Builder<'_>, cmd: &mut Command, stream: bool) -> bool {
+fn run_tests(builder: &Builder<'_>, cmd: &mut BootstrapCommand, stream: bool) -> bool {
+    let cmd = &mut cmd.command;
     cmd.stdout(Stdio::piped());
 
     builder.verbose(|| println!("running: {cmd:?}"));
diff --git a/src/bootstrap/src/utils/shared_helpers.rs b/src/bootstrap/src/utils/shared_helpers.rs
new file mode 100644
index 00000000000..7150c84313c
--- /dev/null
+++ b/src/bootstrap/src/utils/shared_helpers.rs
@@ -0,0 +1,112 @@
+//! This module serves two purposes:
+//!     1. It is part of the `utils` module and used in other parts of bootstrap.
+//!     2. It is embedded inside bootstrap shims to avoid a dependency on the bootstrap library.
+//!        Therefore, this module should never use any other bootstrap module. This reduces binary
+//!        size and improves compilation time by minimizing linking time.
+
+#![allow(dead_code)]
+
+use std::env;
+use std::ffi::OsString;
+use std::fs::OpenOptions;
+use std::io::Write;
+use std::process::Command;
+use std::str::FromStr;
+
+#[cfg(test)]
+mod tests;
+
+/// 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") {
+        "PATH"
+    } else if cfg!(target_vendor = "apple") {
+        "DYLD_LIBRARY_PATH"
+    } else if cfg!(target_os = "haiku") {
+        "LIBRARY_PATH"
+    } else if cfg!(target_os = "aix") {
+        "LIBPATH"
+    } else {
+        "LD_LIBRARY_PATH"
+    }
+}
+
+/// Parses the `dylib_path_var()` environment variable, returning a list of
+/// paths that are members of this lookup path.
+pub fn dylib_path() -> Vec<std::path::PathBuf> {
+    let var = match std::env::var_os(dylib_path_var()) {
+        Some(v) => v,
+        None => return vec![],
+    };
+    std::env::split_paths(&var).collect()
+}
+
+/// Given an executable called `name`, return the filename for the
+/// executable for a particular target.
+pub fn exe(name: &str, target: &str) -> String {
+    if target.contains("windows") {
+        format!("{name}.exe")
+    } else if target.contains("uefi") {
+        format!("{name}.efi")
+    } else {
+        name.to_string()
+    }
+}
+
+/// Parses the value of the "RUSTC_VERBOSE" environment variable and returns it as a `usize`.
+/// If it was not defined, returns 0 by default.
+///
+/// Panics if "RUSTC_VERBOSE" is defined with the value that is not an unsigned integer.
+pub fn parse_rustc_verbose() -> usize {
+    match env::var("RUSTC_VERBOSE") {
+        Ok(s) => usize::from_str(&s).expect("RUSTC_VERBOSE should be an integer"),
+        Err(_) => 0,
+    }
+}
+
+/// Parses the value of the "RUSTC_STAGE" environment variable and returns it as a `String`.
+///
+/// If "RUSTC_STAGE" was not set, the program will be terminated with 101.
+pub fn parse_rustc_stage() -> String {
+    env::var("RUSTC_STAGE").unwrap_or_else(|_| {
+        // Don't panic here; it's reasonable to try and run these shims directly. Give a helpful error instead.
+        eprintln!("rustc shim: FATAL: RUSTC_STAGE was not set");
+        eprintln!("rustc shim: NOTE: use `x.py build -vvv` to see all environment variables set by bootstrap");
+        std::process::exit(101);
+    })
+}
+
+/// Writes the command invocation to a file if `DUMP_BOOTSTRAP_SHIMS` is set during bootstrap.
+///
+/// Before writing it, replaces user-specific values to create generic dumps for cross-environment
+/// comparisons.
+pub fn maybe_dump(dump_name: String, cmd: &Command) {
+    if let Ok(dump_dir) = env::var("DUMP_BOOTSTRAP_SHIMS") {
+        let dump_file = format!("{dump_dir}/{dump_name}");
+
+        let mut file = OpenOptions::new().create(true).append(true).open(dump_file).unwrap();
+
+        let cmd_dump = format!("{:?}\n", cmd);
+        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}");
+
+        file.write_all(cmd_dump.as_bytes()).expect("Unable to write file");
+    }
+}
+
+/// Finds `key` and returns its value from the given list of arguments `args`.
+pub fn parse_value_from_args<'a>(args: &'a [OsString], key: &str) -> Option<&'a str> {
+    let mut args = args.iter();
+    while let Some(arg) = args.next() {
+        let arg = arg.to_str().unwrap();
+
+        if let Some(value) = arg.strip_prefix(&format!("{key}=")) {
+            return Some(value);
+        } else if arg == key {
+            return args.next().map(|v| v.to_str().unwrap());
+        }
+    }
+
+    None
+}
diff --git a/src/bootstrap/src/utils/shared_helpers/tests.rs b/src/bootstrap/src/utils/shared_helpers/tests.rs
new file mode 100644
index 00000000000..da7924276f7
--- /dev/null
+++ b/src/bootstrap/src/utils/shared_helpers/tests.rs
@@ -0,0 +1,28 @@
+use super::parse_value_from_args;
+
+#[test]
+fn test_parse_value_from_args() {
+    let args = vec![
+        "--stage".into(),
+        "1".into(),
+        "--version".into(),
+        "2".into(),
+        "--target".into(),
+        "x86_64-unknown-linux".into(),
+    ];
+
+    assert_eq!(parse_value_from_args(args.as_slice(), "--stage").unwrap(), "1");
+    assert_eq!(parse_value_from_args(args.as_slice(), "--version").unwrap(), "2");
+    assert_eq!(parse_value_from_args(args.as_slice(), "--target").unwrap(), "x86_64-unknown-linux");
+    assert!(parse_value_from_args(args.as_slice(), "random-key").is_none());
+
+    let args = vec![
+        "app-name".into(),
+        "--key".into(),
+        "value".into(),
+        "random-value".into(),
+        "--sysroot=/x/y/z".into(),
+    ];
+    assert_eq!(parse_value_from_args(args.as_slice(), "--key").unwrap(), "value");
+    assert_eq!(parse_value_from_args(args.as_slice(), "--sysroot").unwrap(), "/x/y/z");
+}
diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs
index fd934f18de2..4f0104e4bba 100644
--- a/src/bootstrap/src/utils/tarball.rs
+++ b/src/bootstrap/src/utils/tarball.rs
@@ -5,15 +5,13 @@
 //! In uplifting, a tarball from Stage N captures essential components
 //! to assemble Stage N + 1 compiler.
 
-use std::{
-    path::{Path, PathBuf},
-    process::Command,
-};
+use std::path::{Path, PathBuf};
 
 use crate::core::builder::Builder;
 use crate::core::{build_steps::dist::distdir, builder::Kind};
-use crate::utils::channel;
+use crate::utils::exec::BootstrapCommand;
 use crate::utils::helpers::{move_file, t};
+use crate::utils::{channel, helpers};
 
 #[derive(Copy, Clone)]
 pub(crate) enum OverlayKind {
@@ -300,7 +298,7 @@ impl<'a> Tarball<'a> {
         }
     }
 
-    fn non_bare_args(&self, cmd: &mut Command) {
+    fn non_bare_args(&self, cmd: &mut BootstrapCommand) {
         cmd.arg("--rel-manifest-dir=rustlib")
             .arg("--legacy-manifest-dirs=rustlib,cargo")
             .arg(format!("--product-name={}", self.product_name))
@@ -312,7 +310,7 @@ impl<'a> Tarball<'a> {
             .arg(distdir(self.builder));
     }
 
-    fn run(self, build_cli: impl FnOnce(&Tarball<'a>, &mut Command)) -> GeneratedTarball {
+    fn run(self, build_cli: impl FnOnce(&Tarball<'a>, &mut BootstrapCommand)) -> GeneratedTarball {
         t!(std::fs::create_dir_all(&self.overlay_dir));
         self.builder.create(&self.overlay_dir.join("version"), &self.overlay.version(self.builder));
         if let Some(info) = self.builder.rust_info().info() {
@@ -353,7 +351,35 @@ impl<'a> Tarball<'a> {
         };
 
         cmd.args(["--compression-profile", compression_profile]);
-        self.builder.run(&mut cmd);
+
+        // We want to use a pinned modification time for files in the archive
+        // to achieve better reproducibility. However, using the same mtime for all
+        // releases is not ideal, because it can break e.g. Cargo mtime checking
+        // (https://github.com/rust-lang/rust/issues/125578).
+        // Therefore, we set mtime to the date of the latest commit (if we're managed
+        // by git). In this way, the archive will still be always the same for a given commit
+        // (achieving reproducibility), but it will also change between different commits and
+        // Rust versions, so that it won't break mtime-based caches.
+        //
+        // Note that this only overrides the mtime of files, not directories, due to the
+        // limitations of the tarballer tool. Directories will have their mtime set to 2006.
+
+        // Get the UTC timestamp of the last git commit, if we're under git.
+        // We need to use UTC, so that anyone who tries to rebuild from the same commit
+        // gets the same timestamp.
+        if self.builder.rust_info().is_managed_git_subrepository() {
+            // %ct means committer date
+            let timestamp = helpers::output(
+                &mut helpers::git(Some(&self.builder.src))
+                    .arg("log")
+                    .arg("-1")
+                    .arg("--format=%ct")
+                    .command,
+            );
+            cmd.args(["--override-file-mtime", timestamp.trim()]);
+        }
+
+        cmd.run(self.builder);
 
         // Ensure there are no symbolic links in the tarball. In particular,
         // rustup-toolchain-install-master and most versions of Windows can't handle symbolic links.
diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md
index 824c904e17f..985e3b37422 100644
--- a/src/ci/docker/README.md
+++ b/src/ci/docker/README.md
@@ -271,6 +271,22 @@ For targets: `loongarch64-unknown-linux-gnu`
 - C compiler > gcc version = 13.2.0
 - C compiler > C++ = ENABLE -- to cross compile LLVM
 
+### `loongarch64-linux-musl.defconfig`
+
+For targets: `loongarch64-unknown-linux-musl`
+
+- Path and misc options > Prefix directory = /x-tools/${CT\_TARGET}
+- Path and misc options > Use a mirror = ENABLE
+- Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc
+- Target options > Target Architecture = loongarch
+- Target options > Bitness = 64-bit
+- Operating System > Target OS = linux
+- Operating System > Linux kernel version = 5.19.16
+- Binary utilities > Version of binutils = 2.41
+- C-library > musl version = 1.2.5
+- C compiler > gcc version = 13.2.0
+- C compiler > C++ = ENABLE -- to cross compile LLVM
+
 ### `mips-linux-gnu.defconfig`
 
 For targets: `mips-unknown-linux-gnu`
diff --git a/src/ci/docker/host-x86_64/disabled/riscv64gc-gnu/Dockerfile b/src/ci/docker/host-x86_64/disabled/riscv64gc-gnu/Dockerfile
index a9ffa5918b5..a52c3839196 100644
--- a/src/ci/docker/host-x86_64/disabled/riscv64gc-gnu/Dockerfile
+++ b/src/ci/docker/host-x86_64/disabled/riscv64gc-gnu/Dockerfile
@@ -91,7 +91,9 @@ RUN sh /scripts/sccache.sh
 # Avoid "fatal: detected dubious ownership in repository at '/checkout'" error
 RUN git config --global --add safe.directory /checkout
 
-ENV RUST_CONFIGURE_ARGS --qemu-riscv64-rootfs=/tmp/rootfs
+ENV RUST_CONFIGURE_ARGS \
+    --qemu-riscv64-rootfs=/tmp/rootfs \
+    --set target.riscv64gc-unknown-linux-gnu.linker=riscv64-linux-gnu-gcc
 ENV SCRIPT python3 ../x.py --stage 2 test --host='' --target riscv64gc-unknown-linux-gnu
 
 ENV NO_CHANGE_USER=1
diff --git a/src/ci/docker/host-x86_64/dist-loongarch64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-loongarch64-linux/Dockerfile
index 55c737bd0aa..d3956651663 100644
--- a/src/ci/docker/host-x86_64/dist-loongarch64-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-loongarch64-linux/Dockerfile
@@ -23,7 +23,30 @@ ENV CC_loongarch64_unknown_linux_gnu=loongarch64-unknown-linux-gnu-gcc \
     AR_loongarch64_unknown_linux_gnu=loongarch64-unknown-linux-gnu-ar \
     CXX_loongarch64_unknown_linux_gnu=loongarch64-unknown-linux-gnu-g++
 
+# We re-use the Linux toolchain for bare-metal, because upstream bare-metal
+# target support for LoongArch is only available from GCC 14+.
+#
+# See: https://github.com/gcc-mirror/gcc/commit/976f4f9e4770
+ENV CC_loongarch64_unknown_none=loongarch64-unknown-linux-gnu-gcc \
+    AR_loongarch64_unknown_none=loongarch64-unknown-linux-gnu-ar \
+    CXX_loongarch64_unknown_none=loongarch64-unknown-linux-gnu-g++ \
+    CFLAGS_loongarch64_unknown_none="-ffreestanding -mabi=lp64d" \
+    CXXFLAGS_loongarch64_unknown_none="-ffreestanding -mabi=lp64d" \
+    CC_loongarch64_unknown_none_softfloat=loongarch64-unknown-linux-gnu-gcc \
+    AR_loongarch64_unknown_none_softfloat=loongarch64-unknown-linux-gnu-ar \
+    CXX_loongarch64_unknown_none_softfloat=loongarch64-unknown-linux-gnu-g++ \
+    CFLAGS_loongarch64_unknown_none_softfloat="-ffreestanding -mabi=lp64s -mfpu=none" \
+    CXXFLAGS_loongarch64_unknown_none_softfloat="-ffreestanding -mabi=lp64s -mfpu=none"
+
 ENV HOSTS=loongarch64-unknown-linux-gnu
+ENV TARGETS=$HOSTS
+ENV TARGETS=$TARGETS,loongarch64-unknown-none
+ENV TARGETS=$TARGETS,loongarch64-unknown-none-softfloat
+
+ENV RUST_CONFIGURE_ARGS \
+      --enable-extended \
+      --enable-full-tools \
+      --enable-profiler \
+      --disable-docs
 
-ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
-ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
+ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $TARGETS
diff --git a/src/ci/docker/host-x86_64/dist-loongarch64-musl/Dockerfile b/src/ci/docker/host-x86_64/dist-loongarch64-musl/Dockerfile
new file mode 100644
index 00000000000..62dbfaaa673
--- /dev/null
+++ b/src/ci/docker/host-x86_64/dist-loongarch64-musl/Dockerfile
@@ -0,0 +1,36 @@
+FROM ubuntu:22.04
+
+COPY scripts/cross-apt-packages.sh /scripts/
+RUN sh /scripts/cross-apt-packages.sh
+
+COPY scripts/crosstool-ng-git.sh /scripts/
+RUN sh /scripts/crosstool-ng-git.sh
+
+COPY scripts/rustbuild-setup.sh /scripts/
+RUN sh /scripts/rustbuild-setup.sh
+WORKDIR /tmp
+
+COPY scripts/crosstool-ng-build.sh /scripts/
+COPY host-x86_64/dist-loongarch64-musl/loongarch64-unknown-linux-musl.defconfig /tmp/crosstool.defconfig
+RUN /scripts/crosstool-ng-build.sh
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
+ENV PATH=$PATH:/x-tools/loongarch64-unknown-linux-musl/bin
+
+ENV CC_loongarch64_unknown_linux_musl=loongarch64-unknown-linux-musl-gcc \
+    AR_loongarch64_unknown_linux_musl=loongarch64-unknown-linux-musl-ar \
+    CXX_loongarch64_unknown_linux_musl=loongarch64-unknown-linux-musl-g++
+
+ENV HOSTS=loongarch64-unknown-linux-musl
+
+ENV RUST_CONFIGURE_ARGS \
+      --enable-extended \
+      --enable-full-tools \
+      --enable-profiler \
+      --disable-docs \
+      --set target.loongarch64-unknown-linux-musl.crt-static=false \
+      --musl-root-loongarch64=/x-tools/loongarch64-unknown-linux-musl/loongarch64-unknown-linux-musl/sysroot/usr
+
+ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/host-x86_64/dist-loongarch64-musl/loongarch64-unknown-linux-musl.defconfig b/src/ci/docker/host-x86_64/dist-loongarch64-musl/loongarch64-unknown-linux-musl.defconfig
new file mode 100644
index 00000000000..3ab676ed971
--- /dev/null
+++ b/src/ci/docker/host-x86_64/dist-loongarch64-musl/loongarch64-unknown-linux-musl.defconfig
@@ -0,0 +1,15 @@
+CT_CONFIG_VERSION="4"
+CT_EXPERIMENTAL=y
+CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
+CT_USE_MIRROR=y
+CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc"
+CT_ARCH_LOONGARCH=y
+# CT_DEMULTILIB is not set
+CT_ARCH_USE_MMU=y
+CT_ARCH_ARCH="loongarch64"
+CT_KERNEL_LINUX=y
+CT_LINUX_V_5_19=y
+CT_LIBC_MUSL=y
+CT_CC_GCC_ENABLE_DEFAULT_PIE=y
+CT_CC_LANG_CXX=y
+CT_GETTEXT_NEEDED=y
diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
index bb6254942cb..e3cb396b782 100644
--- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
@@ -121,8 +121,6 @@ ENV TARGETS=$TARGETS,armv7-unknown-linux-gnueabi
 ENV TARGETS=$TARGETS,armv7-unknown-linux-musleabi
 ENV TARGETS=$TARGETS,i686-unknown-freebsd
 ENV TARGETS=$TARGETS,x86_64-unknown-none
-ENV TARGETS=$TARGETS,loongarch64-unknown-none
-ENV TARGETS=$TARGETS,loongarch64-unknown-none-softfloat
 ENV TARGETS=$TARGETS,aarch64-unknown-uefi
 ENV TARGETS=$TARGETS,i686-unknown-uefi
 ENV TARGETS=$TARGETS,x86_64-unknown-uefi
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gccjit.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gccjit.sh
index 5bc6f5cc216..4c80e895fd2 100755
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gccjit.sh
+++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gccjit.sh
@@ -3,7 +3,7 @@
 GIT_REPO="https://github.com/rust-lang/gcc"
 
 # This commit hash needs to be updated to use a more recent gcc fork version.
-GIT_COMMIT="78dc50f0e50e6cd1433149520bd512a4e0eaa1bc"
+GIT_COMMIT="341be3b7d7ac6976cfed8ed59da3573c040d0776"
 
 set -ex
 
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-netbsd/build-netbsd-toolchain.sh b/src/ci/docker/host-x86_64/dist-x86_64-netbsd/build-netbsd-toolchain.sh
index e0c008b76fa..4a42f5da29f 100755
--- a/src/ci/docker/host-x86_64/dist-x86_64-netbsd/build-netbsd-toolchain.sh
+++ b/src/ci/docker/host-x86_64/dist-x86_64-netbsd/build-netbsd-toolchain.sh
@@ -1,7 +1,7 @@
 #!/usr/bin/env bash
 # ignore-tidy-linelength
 
-set -ex
+set -eux
 
 hide_output() {
   set +x
@@ -20,6 +20,22 @@ exit 1
   set -x
 }
 
+# Download, verify SHA512, and remove the downloaded file
+# Usage: <file name> <url> <file sha> <full tar command using fname>
+download() {
+  fname="$1"
+  shift
+  url="$1"
+  shift
+  sha="$1"
+  shift
+
+  curl "$url" -o "$fname"
+  echo "$sha  $fname" | shasum -a 512 --check || exit 1
+  "$@"
+  rm "$fname"
+}
+
 mkdir netbsd
 cd netbsd
 
@@ -27,17 +43,31 @@ mkdir -p /x-tools/x86_64-unknown-netbsd/sysroot
 
 # URL=https://ci-mirrors.rust-lang.org/rustc
 
-SOURCE_URL=https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.0/source/sets
-curl $SOURCE_URL/src.tgz | tar xzf -
-curl $SOURCE_URL/gnusrc.tgz | tar xzf -
-curl $SOURCE_URL/sharesrc.tgz | tar xzf -
-curl $SOURCE_URL/syssrc.tgz | tar xzf -
-
-BINARY_URL=https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.0/amd64/binary/sets
-curl $BINARY_URL/base.tar.xz | \
-  tar xJf - -C /x-tools/x86_64-unknown-netbsd/sysroot ./usr/include ./usr/lib ./lib
-curl $BINARY_URL/comp.tar.xz | \
-  tar xJf - -C /x-tools/x86_64-unknown-netbsd/sysroot ./usr/include ./usr/lib
+# Hashes come from https://cdn.netbsd.org/pub/NetBSD/security/hashes/NetBSD-9.0_hashes.asc
+SRC_SHA=2c791ae009a6929c6fc893ec5df7e62910ee8207e0b2159d6937309c03efe175b6ae1e445829a13d041b6851334ad35c521f2fa03c97675d4a05f1fafe58ede0
+GNUSRC_SHA=3710085a73feecf6a843415271ec794c90146b03f6bbd30f07c9e0c79febf8995d557e40194f1e05db655e4f5ef2fae97563f8456fceaae65d4ea98857a83b1c
+SHARESRC_SHA=f080776ed82c3ac5d6272dee39746f87897d8e6984996caf5bf6d87bf11d9c9e0c1ad5c437c21258bd278bb6fd76974946e878f548517885f71c556096231369
+SYSSRC_SHA=60b9ddf4cc6402256473e2e1eefeabd9001aa4e205208715ecc6d6fc3f5b400e469944580077271b8e80562a4c2f601249e69e07a504f46744e0c50335f1cbf1
+BASE_SHA=b5926b107cebf40c3c19b4f6cd039b610987dd7f819e7cdde3bd1e5230a856906e7930b15ab242d52ced9f0bda01d574be59488b8dbb95fa5df2987d0a70995f
+COMP_SHA=38ea54f30d5fc2afea87e5096f06873e00182789e8ad9cec0cb3e9f7c538c1aa4779e63fd401a36ba02676158e83fa5c95e8e87898db59c1914fb206aecd82d2
+
+# FIXME: the archive URL is being used temporarily while the CDN is down.
+# We should serve this from our own CDN
+# SOURCE_URL=https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.0/source/sets
+SOURCE_URL=http://archive.netbsd.org/pub/NetBSD-archive/NetBSD-9.0/source/sets
+download src.tgz "$SOURCE_URL/src.tgz" "$SRC_SHA" tar xzf src.tgz
+download gnusrc.tgz "$SOURCE_URL/gnusrc.tgz" "$GNUSRC_SHA" tar xzf gnusrc.tgz
+download sharesrc.tgz "$SOURCE_URL/sharesrc.tgz" "$SHARESRC_SHA" tar xzf sharesrc.tgz
+download syssrc.tgz "$SOURCE_URL/syssrc.tgz" "$SYSSRC_SHA" tar xzf syssrc.tgz
+
+# FIXME: the archive URL is being used temporarily while the CDN is down.
+# We should serve this from our own CDN
+# BINARY_URL=https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.0/amd64/binary/sets
+BINARY_URL=http://archive.netbsd.org/pub/NetBSD-archive/NetBSD-9.0/amd64/binary/sets
+download base.tar.xz "$BINARY_URL/base.tar.xz" "$BASE_SHA" \
+  tar xJf base.tar.xz -C /x-tools/x86_64-unknown-netbsd/sysroot ./usr/include ./usr/lib ./lib
+download comp.tar.xz "$BINARY_URL/comp.tar.xz" "$COMP_SHA" \
+  tar xJf comp.tar.xz -C /x-tools/x86_64-unknown-netbsd/sysroot ./usr/include ./usr/lib
 
 cd usr/src
 
diff --git a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile
index 0a49eab4d50..cb17592b201 100644
--- a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile
+++ b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile
@@ -35,4 +35,4 @@ COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/
 # NOTE: intentionally uses python2 for x.py so we can test it still works.
 # validate-toolstate only runs in our CI, so it's ok for it to only support python3.
 ENV SCRIPT TIDY_PRINT_DIFF=1 python2.7 ../x.py test \
-           --stage 0 src/tools/tidy tidyselftest --extra-checks=py:lint
+           --stage 0 src/tools/tidy tidyselftest --extra-checks=py:lint,cpp:fmt
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-integration/Dockerfile b/src/ci/docker/host-x86_64/x86_64-fuchsia/Dockerfile
index a944f370c6b..ba3e8bdb687 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-integration/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-fuchsia/Dockerfile
@@ -1,5 +1,6 @@
 # This job builds a toolchain capable of building Fuchsia, and then builds
-# Fuchsia. See the build-fuchsia.sh script in this directory for more details.
+# Fuchsia as an integration test of the toolchain. See the build-fuchsia.sh
+# script in this directory for more details.
 
 FROM ubuntu:22.04
 
@@ -24,7 +25,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   && rm -rf /var/lib/apt/lists/*
 
 # Duplicated in dist-various-2 Dockerfile.
-# FIXME: Move to canonical triple
 ENV \
     AR_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-ar \
     CC_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-clang \
@@ -48,10 +48,6 @@ ENV CARGO_TARGET_X86_64_UNKNOWN_FUCHSIA_RUSTFLAGS \
 
 ENV TARGETS=x86_64-unknown-fuchsia
 ENV TARGETS=$TARGETS,x86_64-unknown-linux-gnu
-ENV TARGETS=$TARGETS,wasm32-unknown-unknown
-
-# Fuchsia clang does not have wasm target enabled, use system clang.
-ENV CC_wasm32_unknown_unknown=clang-15
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
@@ -76,4 +72,4 @@ ENV RUST_CONFIGURE_ARGS \
   --set target.x86_64-unknown-fuchsia.linker=/usr/local/bin/ld.lld
 ENV SCRIPT \
     python3 ../x.py install --target $TARGETS compiler/rustc library/std clippy && \
-    bash ../src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh
+    bash ../src/ci/docker/host-x86_64/x86_64-fuchsia/build-fuchsia.sh
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh b/src/ci/docker/host-x86_64/x86_64-fuchsia/build-fuchsia.sh
index 2bb1d0a6338..c806b886dae 100755
--- a/src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh
+++ b/src/ci/docker/host-x86_64/x86_64-fuchsia/build-fuchsia.sh
@@ -5,14 +5,14 @@
 #
 # You may run this script locally using Docker with the following command:
 #
-# $ src/ci/docker/run.sh x86_64-gnu-integration
+# $ src/ci/docker/run.sh x86_64-fuchsia
 #
 # Alternatively, from within the container with --dev, assuming you have made it
 # as far as building the toolchain with the above command:
 #
-# $ src/ci/docker/run.sh --dev x86_64-gnu-integration
+# $ src/ci/docker/run.sh --dev x86_64-fuchsia
 # docker# git config --global --add safe.directory /checkout/obj/fuchsia
-# docker# ../src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh
+# docker# ../src/ci/docker/host-x86_64/x86_64-fuchsia/build-fuchsia.sh
 #
 # Also see the docs in the rustc-dev-guide for more info:
 # https://github.com/rust-lang/rustc-dev-guide/pull/1989
@@ -21,7 +21,7 @@ set -euf -o pipefail
 
 # Set this variable to 1 to disable updating the Fuchsia checkout. This is
 # useful for making local changes. You can find the Fuchsia checkout in
-# `obj/x86_64-gnu-integration/fuchsia` in your local checkout after running this
+# `obj/x86_64-fuchsia/fuchsia` in your local checkout after running this
 # job for the first time.
 KEEP_CHECKOUT=
 
@@ -35,7 +35,7 @@ PICK_REFS=()
 # commit hash of fuchsia.git and some other repos in the "monorepo" checkout, in
 # addition to versions of prebuilts. It should be bumped regularly by the
 # Fuchsia team – we aim for every 1-2 months.
-INTEGRATION_SHA=737ebdd83afa47b742ca8325fad0176952fcefbd
+INTEGRATION_SHA=d1d2f20efe46e22be179953dd6726c96eced54ab
 
 checkout=fuchsia
 jiri=.jiri_root/bin/jiri
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 50c2e5e29f0..47d04a52883 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.17.2
\ No newline at end of file
+0.18.0
\ No newline at end of file
diff --git a/src/ci/docker/host-x86_64/rfl/Dockerfile b/src/ci/docker/host-x86_64/x86_64-rust-for-linux/Dockerfile
index 97298519cf2..97298519cf2 100644
--- a/src/ci/docker/host-x86_64/rfl/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-rust-for-linux/Dockerfile
diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh
index a4c59b3067e..40f42171411 100755
--- a/src/ci/docker/run.sh
+++ b/src/ci/docker/run.sh
@@ -93,8 +93,7 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then
     docker --version
 
     REGISTRY=ghcr.io
-    # PR CI runs on rust-lang, but we want to use the cache from rust-lang-ci
-    REGISTRY_USERNAME=rust-lang-ci
+    REGISTRY_USERNAME=${GITHUB_REPOSITORY_OWNER:-rust-lang-ci}
     # Tag used to push the final Docker image, so that it can be pulled by e.g. rustup
     IMAGE_TAG=${REGISTRY}/${REGISTRY_USERNAME}/rust-ci:${cksum}
     # Tag used to cache the Docker build
diff --git a/src/ci/docker/scripts/crosstool-ng-git.sh b/src/ci/docker/scripts/crosstool-ng-git.sh
new file mode 100644
index 00000000000..2a10e262df8
--- /dev/null
+++ b/src/ci/docker/scripts/crosstool-ng-git.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+set -ex
+
+URL=https://github.com/crosstool-ng/crosstool-ng
+REV=c64500d94be92ed1bcdfdef911048a14e216a5e1
+
+mkdir crosstool-ng
+cd crosstool-ng
+git init
+git fetch --depth=1 ${URL} ${REV}
+git reset --hard FETCH_HEAD
+./bootstrap
+./configure --prefix=/usr/local
+make -j$(nproc)
+make install
+cd ..
+rm -rf crosstool-ng
diff --git a/src/ci/docker/scripts/fuchsia-test-runner.py b/src/ci/docker/scripts/fuchsia-test-runner.py
index 115ee69a589..00269e68422 100755
--- a/src/ci/docker/scripts/fuchsia-test-runner.py
+++ b/src/ci/docker/scripts/fuchsia-test-runner.py
@@ -8,8 +8,6 @@ https://doc.rust-lang.org/stable/rustc/platform-support/fuchsia.html#aarch64-unk
 """
 
 import argparse
-from concurrent.futures import ThreadPoolExecutor
-from dataclasses import dataclass
 import glob
 import io
 import json
@@ -20,6 +18,8 @@ import shlex
 import shutil
 import subprocess
 import sys
+from concurrent.futures import ThreadPoolExecutor
+from dataclasses import dataclass
 from pathlib import Path
 from typing import ClassVar, List, Optional
 
@@ -42,12 +42,8 @@ def check_call_with_logging(
                 for line in pipe:
                     handler(line.rstrip())
 
-            executor_out = executor.submit(
-                exhaust_pipe, stdout_handler, process.stdout
-            )
-            executor_err = executor.submit(
-                exhaust_pipe, stderr_handler, process.stderr
-            )
+            executor_out = executor.submit(exhaust_pipe, stdout_handler, process.stdout)
+            executor_err = executor.submit(exhaust_pipe, stderr_handler, process.stderr)
             executor_out.result()
             executor_err.result()
     retcode = process.poll()
@@ -112,7 +108,7 @@ def atomic_link(link: Path, target: Path):
             os.remove(tmp_file)
 
 
-@dataclass(kw_only=True)
+@dataclass
 class TestEnvironment:
     rust_build_dir: Path
     sdk_dir: Path
@@ -203,9 +199,7 @@ class TestEnvironment:
             raise Exception(f"Unreadable build-id for binary {binary}")
         data = json.loads(process.stdout)
         if len(data) != 1:
-            raise Exception(
-                f"Unreadable output from llvm-readelf for binary {binary}"
-            )
+            raise Exception(f"Unreadable output from llvm-readelf for binary {binary}")
         notes = data[0]["Notes"]
         for note in notes:
             note_section = note["NoteSection"]
@@ -265,19 +259,10 @@ class TestEnvironment:
     def setup_logging(self, log_to_file=False):
         fs = logging.Formatter("%(asctime)s %(levelname)s:%(name)s:%(message)s")
         if log_to_file:
-            logfile_handler = logging.FileHandler(
-                self.tmp_dir().joinpath("log")
-            )
+            logfile_handler = logging.FileHandler(self.tmp_dir().joinpath("log"))
             logfile_handler.setLevel(logging.DEBUG)
             logfile_handler.setFormatter(fs)
             logging.getLogger().addHandler(logfile_handler)
-        stream_handler = logging.StreamHandler(sys.stdout)
-        stream_handler.setFormatter(fs)
-        if self.verbose:
-            stream_handler.setLevel(logging.DEBUG)
-        else:
-            stream_handler.setLevel(logging.INFO)
-        logging.getLogger().addHandler(stream_handler)
         logging.getLogger().setLevel(logging.DEBUG)
 
     @property
@@ -454,9 +439,7 @@ class TestEnvironment:
         # Initialize temp directory
         os.makedirs(self.tmp_dir(), exist_ok=True)
         if len(os.listdir(self.tmp_dir())) != 0:
-            raise Exception(
-                f"Temp directory is not clean (in {self.tmp_dir()})"
-            )
+            raise Exception(f"Temp directory is not clean (in {self.tmp_dir()})")
         self.setup_logging(log_to_file=True)
         os.mkdir(self.output_dir)
 
@@ -493,9 +476,7 @@ class TestEnvironment:
             shutil.rmtree(self.local_pb_path, ignore_errors=True)
 
             # Look up the product bundle transfer manifest.
-            self.env_logger.info(
-                "Looking up the product bundle transfer manifest..."
-            )
+            self.env_logger.info("Looking up the product bundle transfer manifest...")
             product_name = "minimal." + self.triple_to_arch(self.target)
             sdk_version = self.read_sdk_version()
 
@@ -517,9 +498,7 @@ class TestEnvironment:
             )
 
             try:
-                transfer_manifest_url = json.loads(output)[
-                    "transfer_manifest_url"
-                ]
+                transfer_manifest_url = json.loads(output)["transfer_manifest_url"]
             except Exception as e:
                 print(e)
                 raise Exception("Unable to parse transfer manifest") from e
@@ -769,9 +748,7 @@ class TestEnvironment:
             # Use /tmp as the test temporary directory
             env_vars += '\n            "RUST_TEST_TMPDIR=/tmp",'
 
-            cml.write(
-                self.CML_TEMPLATE.format(env_vars=env_vars, exe_name=exe_name)
-            )
+            cml.write(self.CML_TEMPLATE.format(env_vars=env_vars, exe_name=exe_name))
 
         runner_logger.info("Compiling CML...")
 
@@ -922,20 +899,16 @@ class TestEnvironment:
 
         if stdout_path is not None:
             if not os.path.exists(stdout_path):
-                runner_logger.error(
-                    f"stdout file {stdout_path} does not exist."
-                )
+                runner_logger.error(f"stdout file {stdout_path} does not exist.")
             else:
                 with open(stdout_path, encoding="utf-8", errors="ignore") as f:
-                    runner_logger.info(f.read())
+                    sys.stdout.write(f.read())
         if stderr_path is not None:
             if not os.path.exists(stderr_path):
-                runner_logger.error(
-                    f"stderr file {stderr_path} does not exist."
-                )
+                runner_logger.error(f"stderr file {stderr_path} does not exist.")
             else:
                 with open(stderr_path, encoding="utf-8", errors="ignore") as f:
-                    runner_logger.error(f.read())
+                    sys.stderr.write(f.read())
 
         runner_logger.info("Done!")
         return return_code
@@ -1037,7 +1010,7 @@ class TestEnvironment:
                 f"--symbol-path={self.rust_dir}/lib/rustlib/{self.target}/lib",
             ]
 
-      # Add rust source if it's available
+        # Add rust source if it's available
         rust_src_map = None
         if args.rust_src is not None:
             # This matches the remapped prefix used by compiletest. There's no
@@ -1210,7 +1183,7 @@ def main():
     start_parser.add_argument(
         "--use-local-product-bundle-if-exists",
         help="if the product bundle already exists in the local path, use "
-            "it instead of downloading it again",
+        "it instead of downloading it again",
         action="store_true",
     )
     start_parser.set_defaults(func=start)
@@ -1246,9 +1219,7 @@ def main():
     )
     cleanup_parser.set_defaults(func=cleanup)
 
-    syslog_parser = subparsers.add_parser(
-        "syslog", help="prints the device syslog"
-    )
+    syslog_parser = subparsers.add_parser("syslog", help="prints the device syslog")
     syslog_parser.set_defaults(func=syslog)
 
     debug_parser = subparsers.add_parser(
diff --git a/src/ci/github-actions/calculate-job-matrix.py b/src/ci/github-actions/calculate-job-matrix.py
index 4f9bc39a628..d03bbda1008 100755
--- a/src/ci/github-actions/calculate-job-matrix.py
+++ b/src/ci/github-actions/calculate-job-matrix.py
@@ -91,21 +91,17 @@ def find_run_type(ctx: GitHubCtx) -> Optional[WorkflowRunType]:
     if ctx.event_name == "pull_request":
         return PRRunType()
     elif ctx.event_name == "push":
-        old_bors_try_build = (
-            ctx.ref in ("refs/heads/try", "refs/heads/try-perf") and
-            ctx.repository == "rust-lang-ci/rust"
+        try_build = ctx.ref in (
+            "refs/heads/try",
+            "refs/heads/try-perf",
+            "refs/heads/automation/bors/try"
         )
-        new_bors_try_build = (
-            ctx.ref == "refs/heads/automation/bors/try" and
-            ctx.repository == "rust-lang/rust"
-        )
-        try_build = old_bors_try_build or new_bors_try_build
 
         if try_build:
             jobs = get_custom_jobs(ctx)
             return TryRunType(custom_jobs=jobs)
 
-        if ctx.ref == "refs/heads/auto" and ctx.repository == "rust-lang-ci/rust":
+        if ctx.ref == "refs/heads/auto":
             return AutoRunType()
 
     return None
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index 4366a92fbcd..a6e12c6ff95 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -144,6 +144,9 @@ auto:
   - image: dist-loongarch64-linux
     <<: *job-linux-4c
 
+  - image: dist-loongarch64-musl
+    <<: *job-linux-4c
+
   - image: dist-ohos
     <<: *job-linux-4c
 
@@ -205,6 +208,18 @@ auto:
   - image: test-various
     <<: *job-linux-4c
 
+  - image: x86_64-fuchsia
+    # Only run this job on the nightly channel. Fuchsia requires
+    # nightly features to compile, and this job would fail if
+    # executed on beta and stable.
+    only_on_channel: nightly
+    <<: *job-linux-8c
+
+  # Tests integration with Rust for Linux.
+  # Builds stage 1 compiler and tries to compile a few RfL examples with it.
+  - image: x86_64-rust-for-linux
+    <<: *job-linux-8c
+
   - image: x86_64-gnu
     <<: *job-linux-4c
 
@@ -226,13 +241,6 @@ auto:
   - image: x86_64-gnu-aux
     <<: *job-linux-4c
 
-  - image: x86_64-gnu-integration
-    # Only run this job on the nightly channel. Fuchsia requires
-    # nightly features to compile, and this job would fail if
-    # executed on beta and stable.
-    only_on_channel: nightly
-    <<: *job-linux-8c
-
   - image: x86_64-gnu-debug
     <<: *job-linux-4c
 
@@ -462,8 +470,3 @@ auto:
       RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler
       SCRIPT: python x.py dist bootstrap --include-default-paths
     <<: *job-windows-8c
-
-  # Tests integration with Rust for Linux.
-  # Builds stage 1 compiler and tries to compile a few RfL examples with it.
-  - image: rfl
-    <<: *job-linux-8c
diff --git a/src/ci/run.sh b/src/ci/run.sh
index efaf70078c4..869f75e923d 100755
--- a/src/ci/run.sh
+++ b/src/ci/run.sh
@@ -85,6 +85,10 @@ fi
 # space required for CI artifacts.
 RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --dist-compression-formats=xz"
 
+if [ "$EXTERNAL_LLVM" = "1" ]; then
+  RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.lld=false"
+fi
+
 # Enable the `c` feature for compiler_builtins, but only when the `compiler-rt` source is available
 # (to avoid spending a lot of time cloning llvm)
 if [ "$EXTERNAL_LLVM" = "" ]; then
diff --git a/src/doc/book b/src/doc/book
-Subproject 45c1a6d69edfd1fc91fb7504cb73958dbd09441
+Subproject f1e49bf7a8ea6c31ce016a52b8a4f6e1ffcfbc6
diff --git a/src/doc/edition-guide b/src/doc/edition-guide
-Subproject cb58c430b4e8054c2cb81d2d4434092c482a93d
+Subproject 941db8b3df45fd46cd87b50a5c86714b91dcde9
diff --git a/src/doc/reference b/src/doc/reference
-Subproject 0b805c65804019b0ac8f2fe3117afad82a6069b
+Subproject 1ae3deebc3ac16e276b6558e01420f8e605def0
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject b1d97bd6113aba732b2091ce093c76f2d05bb8a
+Subproject 658c6c27cb975b92227936024816986c2d3716f
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
-Subproject aec82168dd3121289a194b381f56076fc789a4d
+Subproject d6e3a32a557db5902e714604def8015d6bb7e0f
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index e76ebb8f8aa..1a8ff931f01 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -47,7 +47,7 @@
     - [\*-linux-ohos](platform-support/openharmony.md)
     - [\*-hurd-gnu](platform-support/hurd.md)
     - [aarch64-unknown-teeos](platform-support/aarch64-unknown-teeos.md)
-    - [\*-esp-espidf](platform-support/esp-idf.md)
+    - [\*-espidf](platform-support/esp-idf.md)
     - [\*-unknown-fuchsia](platform-support/fuchsia.md)
     - [\*-kmc-solid_\*](platform-support/kmc-solid.md)
     - [csky-unknown-linux-gnuabiv2\*](platform-support/csky-unknown-linux-gnuabiv2.md)
@@ -60,6 +60,7 @@
     - [mipsel-sony-psx](platform-support/mipsel-sony-psx.md)
     - [mipsisa\*r6\*-unknown-linux-gnu\*](platform-support/mips-release-6.md)
     - [nvptx64-nvidia-cuda](platform-support/nvptx64-nvidia-cuda.md)
+    - [powerpc-unknown-openbsd](platform-support/powerpc-unknown-openbsd.md)
     - [powerpc64-ibm-aix](platform-support/aix.md)
     - [riscv32im-risc0-zkvm-elf](platform-support/riscv32im-risc0-zkvm-elf.md)
     - [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md)
@@ -81,6 +82,7 @@
     - [x86_64-fortanix-unknown-sgx](platform-support/x86_64-fortanix-unknown-sgx.md)
     - [x86_64-unknown-linux-none.md](platform-support/x86_64-unknown-linux-none.md)
     - [x86_64-unknown-none](platform-support/x86_64-unknown-none.md)
+    - [xtensa-\*-none-elf](platform-support/xtensa.md)
 - [Targets](targets/index.md)
     - [Built-in Targets](targets/built-in.md)
     - [Custom Targets](targets/custom.md)
diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md
index babe2bc342b..cd10168bc1c 100644
--- a/src/doc/rustc/src/codegen-options/index.md
+++ b/src/doc/rustc/src/codegen-options/index.md
@@ -184,20 +184,9 @@ incremental files will be stored.
 
 ## inline-threshold
 
-This option lets you set the default threshold for inlining a function. It
-takes an unsigned integer as a value. Inlining is based on a cost model, where
-a higher threshold will allow more inlining.
-
-The default depends on the [opt-level](#opt-level):
-
-| opt-level | Threshold |
-|-----------|-----------|
-| 0         | N/A, only inlines always-inline functions |
-| 1         | N/A, only inlines always-inline functions and LLVM lifetime intrinsics |
-| 2         | 225 |
-| 3         | 275 |
-| s         | 75 |
-| z         | 25 |
+This option is deprecated and does nothing.
+
+Consider using `-Cllvm-args=--inline-threshold=...`.
 
 ## instrument-coverage
 
diff --git a/src/doc/rustc/src/lints/levels.md b/src/doc/rustc/src/lints/levels.md
index 93892d6ade6..18e827bd3c9 100644
--- a/src/doc/rustc/src/lints/levels.md
+++ b/src/doc/rustc/src/lints/levels.md
@@ -1,12 +1,13 @@
 # Lint Levels
 
-In `rustc`, lints are divided into five *levels*:
+In `rustc`, lints are divided into six *levels*:
 
 1. allow
-2. warn
-3. force-warn
-4. deny
-5. forbid
+2. expect
+3. warn
+4. force-warn
+5. deny
+6. forbid
 
 Each lint has a default level (explained in the lint listing later in this
 chapter), and the compiler has a default warning level. First, let's explain
@@ -33,6 +34,40 @@ But this code violates the `missing_docs` lint.
 These lints exist mostly to be manually turned on via configuration, as we'll
 talk about later in this section.
 
+## expect
+
+Sometimes, it can be helpful to suppress lints, but at the same time ensure that
+the code in question still emits them. The 'expect' level does exactly this. If
+the lint in question is not emitted, the `unfulfilled_lint_expectation` lint
+triggers on the `expect` attribute, notifying you that the expectation is no
+longer fulfilled.
+
+```rust
+fn main() {
+    #[expect(unused_variables)]
+    let unused = "Everyone ignores me";
+
+    #[expect(unused_variables)] // `unused_variables` lint is not emitted
+    let used = "I'm useful";    // the expectation is therefore unfulfilled
+    println!("The `used` value is equal to: {:?}", used);
+}
+```
+
+This will produce the following warning:
+
+```txt
+warning: this lint expectation is unfulfilled
+ --> src/main.rs:7:14
+  |
+7 |     #[expect(unused_variables)]
+  |              ^^^^^^^^^^^^^^^^
+  |
+  = note: `#[warn(unfulfilled_lint_expectations)]` on by default
+```
+
+This level can only be defined via the `#[expect]` attribute, there is no equivalent
+flag. Lints with the special 'force-warn' level will still be emitted as usual.
+
 ## warn
 
 The 'warn' lint level will produce a warning if you violate the lint. For example,
@@ -240,6 +275,21 @@ And use multiple attributes together:
 pub fn foo() {}
 ```
 
+All lint attributes support an additional `reason` parameter, to give context why
+a certain attribute was added. This reason will be displayed as part of the lint
+message, if the lint is emitted at the defined level.
+
+```rust
+use std::path::PathBuf;
+pub fn get_path() -> PathBuf {
+    #[allow(unused_mut, reason = "this is only modified on some platforms")]
+    let mut file_name = PathBuf::from("git");
+    #[cfg(target_os = "windows")]
+    file_name.set_extension("exe");
+    file_name
+}
+```
+
 ### Capping lints
 
 `rustc` supports a flag, `--cap-lints LEVEL` that sets the "lint cap level."
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 834e909c065..f5cd4bd217a 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -93,6 +93,7 @@ target | notes
 `arm-unknown-linux-gnueabihf` | Armv6 Linux, hardfloat (kernel 3.2, glibc 2.17)
 `armv7-unknown-linux-gnueabihf` | Armv7-A Linux, hardfloat (kernel 3.2, glibc 2.17)
 [`loongarch64-unknown-linux-gnu`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19, glibc 2.36)
+[`loongarch64-unknown-linux-musl`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19, musl 1.2.5)
 `powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 3.2, glibc 2.17)
 `powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 3.2, glibc 2.17)
 `powerpc64le-unknown-linux-gnu` | PPC64LE Linux (kernel 3.10, glibc 2.17)
@@ -118,7 +119,7 @@ The `std` column in the table below has the following meanings:
 
 * ✓ indicates the full standard library is available.
 * \* indicates the target only supports [`no_std`] development.
-* ? indicates the standard library support is unknown or a work-in-progress.
+* ? indicates the standard library support is a work-in-progress.
 
 [`no_std`]: https://rust-embedded.github.io/book/intro/no-std.html
 
@@ -167,12 +168,12 @@ target | std | notes
 `i686-unknown-freebsd` | ✓ | 32-bit FreeBSD [^x86_32-floats-return-ABI]
 `i686-unknown-linux-musl` | ✓ | 32-bit Linux with musl 1.2.3 [^x86_32-floats-return-ABI]
 [`i686-unknown-uefi`](platform-support/unknown-uefi.md) | ? | 32-bit UEFI
-[`loongarch64-unknown-none`](platform-support/loongarch-none.md) | * |  | LoongArch64 Bare-metal (LP64D ABI)
-[`loongarch64-unknown-none-softfloat`](platform-support/loongarch-none.md) | * |  | LoongArch64 Bare-metal (LP64S ABI)
+[`loongarch64-unknown-none`](platform-support/loongarch-none.md) | * | LoongArch64 Bare-metal (LP64D ABI)
+[`loongarch64-unknown-none-softfloat`](platform-support/loongarch-none.md) | * | LoongArch64 Bare-metal (LP64S ABI)
 [`nvptx64-nvidia-cuda`](platform-support/nvptx64-nvidia-cuda.md) | * | --emit=asm generates PTX code that [runs on NVIDIA GPUs]
 [`riscv32imac-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | Bare RISC-V (RV32IMAC ISA)
 [`riscv32i-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | Bare RISC-V (RV32I ISA)
-[`riscv32im-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * |  | Bare RISC-V (RV32IM ISA)
+[`riscv32im-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | Bare RISC-V (RV32IM ISA)
 [`riscv32imc-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | Bare RISC-V (RV32IMC ISA)
 [`riscv32imafc-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | Bare RISC-V (RV32IMAFC ISA)
 `riscv64gc-unknown-none-elf` | * | Bare RISC-V (RV64IMAFDC ISA)
@@ -192,7 +193,7 @@ target | std | notes
 `wasm32-unknown-unknown` | ✓ | WebAssembly
 `wasm32-wasi` | ✓ | WebAssembly with WASI (undergoing a [rename to `wasm32-wasip1`][wasi-rename])
 [`wasm32-wasip1`](platform-support/wasm32-wasip1.md) | ✓ | WebAssembly with WASI
-[`wasm32-wasip1-threads`](platform-support/wasm32-wasip1-threads.md) | ✓ |  | WebAssembly with WASI Preview 1 and threads
+[`wasm32-wasip1-threads`](platform-support/wasm32-wasip1-threads.md) | ✓ | WebAssembly with WASI Preview 1 and threads
 [`x86_64-apple-ios`](platform-support/apple-ios.md) | ✓ | 64-bit x86 iOS
 [`x86_64-fortanix-unknown-sgx`](platform-support/x86_64-fortanix-unknown-sgx.md) | ✓ | [Fortanix ABI] for 64-bit Intel SGX
 `x86_64-fuchsia` | ✓ | Alias for `x86_64-unknown-fuchsia`
@@ -305,7 +306,6 @@ target | std | host | notes
 `i686-uwp-windows-msvc` | ✓ |  | [^x86_32-floats-return-ABI]
 [`i686-win7-windows-msvc`](platform-support/win7-windows-msvc.md) | ✓ |   | 32-bit Windows 7 support [^x86_32-floats-return-ABI]
 `i686-wrs-vxworks` | ? |  | [^x86_32-floats-return-ABI]
-[`loongarch64-unknown-linux-musl`](platform-support/loongarch-linux.md) | ? |  | LoongArch64 Linux (LP64D ABI) with musl 1.2.3
 [`m68k-unknown-linux-gnu`](platform-support/m68k-unknown-linux-gnu.md) | ? |  | Motorola 680x0 Linux
 `mips-unknown-linux-gnu` | ✓ | ✓ | MIPS Linux (kernel 4.4, glibc 2.23)
 `mips-unknown-linux-musl` | ✓ |  | MIPS Linux with musl 1.2.3
@@ -330,7 +330,7 @@ target | std | host | notes
 `powerpc-unknown-linux-gnuspe` | ✓ |  | PowerPC SPE Linux
 `powerpc-unknown-linux-musl` | ? |  | PowerPC Linux with musl 1.2.3
 [`powerpc-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD 32-bit powerpc systems
-`powerpc-unknown-openbsd` | ? |  |
+[`powerpc-unknown-openbsd`](platform-support/powerpc-unknown-openbsd.md) | * |  |
 `powerpc-wrs-vxworks-spe` | ? |  |
 `powerpc-wrs-vxworks` | ? |  |
 `powerpc64-unknown-freebsd` | ✓ | ✓ | PPC64 FreeBSD (ELFv1 and ELFv2)
@@ -384,8 +384,11 @@ target | std | host | notes
 `x86_64-wrs-vxworks` | ? |  |
 [`x86_64h-apple-darwin`](platform-support/x86_64h-apple-darwin.md) | ✓ | ✓ | macOS with late-gen Intel (at least Haswell)
 [`x86_64-unknown-linux-none`](platform-support/x86_64-unknown-linux-none.md) | * |  | 64-bit Linux with no libc
-`xtensa-esp32-none-elf` |  |  | Xtensa ESP32
-`xtensa-esp32s2-none-elf` |  |  | Xtensa ESP32-S2
-`xtensa-esp32s3-none-elf` |  |  | Xtensa ESP32-S3
+[`xtensa-esp32-none-elf`](platform-support/xtensa.md) | * |  | Xtensa ESP32
+[`xtensa-esp32-espidf`](platform-support/esp-idf.md) | ✓ |  | Xtensa ESP32
+[`xtensa-esp32s2-none-elf`](platform-support/xtensa.md) | * |  | Xtensa ESP32-S2
+[`xtensa-esp32s2-espidf`](platform-support/esp-idf.md) | ✓ |  | Xtensa ESP32-S2
+[`xtensa-esp32s3-none-elf`](platform-support/xtensa.md) | * |  | Xtensa ESP32-S3
+[`xtensa-esp32s3-espidf`](platform-support/esp-idf.md) | ✓ |  | Xtensa ESP32-S3
 
 [runs on NVIDIA GPUs]: https://github.com/japaric-archived/nvptx#targets
diff --git a/src/doc/rustc/src/platform-support/esp-idf.md b/src/doc/rustc/src/platform-support/esp-idf.md
index 1f8d9859809..91d7d66627d 100644
--- a/src/doc/rustc/src/platform-support/esp-idf.md
+++ b/src/doc/rustc/src/platform-support/esp-idf.md
@@ -1,4 +1,4 @@
-# `*-esp-espidf`
+# `*-espidf`
 
 **Tier: 3**
 
@@ -8,18 +8,22 @@ Targets for the [ESP-IDF](https://github.com/espressif/esp-idf) development fram
 
 - Ivan Markov [@ivmarkov](https://github.com/ivmarkov)
 - Scott Mabin [@MabezDev](https://github.com/MabezDev)
+- Sergio Gasquez [@SergioGasquez](https://github.com/SergioGasquez)
 
 ## Requirements
 
 The target names follow this format: `$ARCH-esp-espidf`, where `$ARCH` specifies the target processor architecture. The following targets are currently defined:
 
-| Target name              | Target CPU(s)                                                   | Minimum ESP-IDF version |
-| ------------------------ | --------------------------------------------------------------- | ----------------------- |
-| `riscv32imc-esp-espidf`  | [ESP32-C2](https://www.espressif.com/en/products/socs/esp32-c2) | `v5.0`                  |
-| `riscv32imc-esp-espidf`  | [ESP32-C3](https://www.espressif.com/en/products/socs/esp32-c3) | `v4.3`                  |
-| `riscv32imac-esp-espidf` | [ESP32-C6](https://www.espressif.com/en/products/socs/esp32-c6) | `v5.1`                  |
-| `riscv32imac-esp-espidf` | [ESP32-H2](https://www.espressif.com/en/products/socs/esp32-h2) | `v5.1`                  |
-| `riscv32imafc-esp-espidf`| [ESP32-P4](https://www.espressif.com/en/news/ESP32-P4)          | `v5.2`                  |
+| Target name               | Target CPU(s)                                                   | Minimum ESP-IDF version |
+| ------------------------- | --------------------------------------------------------------- | ----------------------- |
+| `riscv32imc-esp-espidf`   | [ESP32-C2](https://www.espressif.com/en/products/socs/esp32-c2) | `v5.0`                  |
+| `riscv32imc-esp-espidf`   | [ESP32-C3](https://www.espressif.com/en/products/socs/esp32-c3) | `v4.4`                  |
+| `riscv32imac-esp-espidf`  | [ESP32-C6](https://www.espressif.com/en/products/socs/esp32-c6) | `v5.1`                  |
+| `riscv32imac-esp-espidf`  | [ESP32-H2](https://www.espressif.com/en/products/socs/esp32-h2) | `v5.1`                  |
+| `riscv32imafc-esp-espidf` | [ESP32-P4](https://www.espressif.com/en/news/ESP32-P4)          | `v5.2`                  |
+| `xtensa-esp32-espidf`     | [ESP32](https://www.espressif.com/en/products/socs/esp32)       | `v4.4`                  |
+| `xtensa-esp32s2-espidf`   | [ESP32-S2](https://www.espressif.com/en/products/socs/esp32-s2) | `v4.4`                  |
+| `xtensa-esp32s3-espidf`   | [ESP32-S3](https://www.espressif.com/en/products/socs/esp32-s3) | `v4.4`                  |
 
 It is recommended to use the latest ESP-IDF stable release if possible.
 
diff --git a/src/doc/rustc/src/platform-support/loongarch-linux.md b/src/doc/rustc/src/platform-support/loongarch-linux.md
index e8f55b8bfce..45eb0a81216 100644
--- a/src/doc/rustc/src/platform-support/loongarch-linux.md
+++ b/src/doc/rustc/src/platform-support/loongarch-linux.md
@@ -1,30 +1,24 @@
-# loongarch\*-unknown-linux-\*
+# `loongarch*-unknown-linux-*`
 
-**Tier: 2**
+**Tier: 2 (with Host Tools)**
 
-[LoongArch] is a new RISC ISA developed by Loongson Technology Corporation Limited.
+[LoongArch][la-docs] Linux targets.
+LoongArch is a RISC ISA developed by Loongson Technology Corporation Limited.
 
-[LoongArch]: https://loongson.github.io/LoongArch-Documentation/README-EN.html
+| Target | Description |
+|--------|-------------|
+| `loongarch64-unknown-linux-gnu` | LoongArch64 Linux, LP64D ABI (kernel 5.19, glibc 2.36) |
+| `loongarch64-unknown-linux-musl` | LoongArch64 Linux, LP64D ABI (kernel 5.19, musl 1.2.5) |
 
-The target name follow this format: `<machine>-<vendor>-<os><fabi_suffix>`, where `<machine>` specifies the CPU family/model, `<vendor>` specifies the vendor and `<os>` the operating system name.
-While the integer base ABI is implied by the machine field, the floating point base ABI type is encoded into the os field of the specifier using the string suffix `<fabi-suffix>`.
+These support both native and cross builds, and have full support for `std`.
 
-|    `<fabi-suffix>`     |                           `Description`                            |
-|------------------------|--------------------------------------------------------------------|
-|          f64           | The base ABI use 64-bits FPRs for parameter passing. (lp64d)|
-|          f32           | The base ABI uses 32-bit FPRs for parameter passing. (lp64f)|
-|          sf            | The base ABI uses no FPR for parameter passing. (lp64s)     |
+Reference material:
 
-<br>
+* [LoongArch ISA manuals][la-docs]
+* [Application Binary Interface for the LoongArch&trade; Architecture][la-abi-specs]
 
-|`ABI type(Base ABI/ABI extension)`| `C library` | `kernel` |          `target tuple`          |
-|----------------------------------|-------------|----------|----------------------------------|
-|           lp64d/base             |   glibc     |  linux   | loongarch64-unknown-linux-gnu |
-|           lp64f/base             |   glibc     |  linux   | loongarch64-unknown-linux-gnuf32 |
-|           lp64s/base             |   glibc     |  linux   | loongarch64-unknown-linux-gnusf  |
-|           lp64d/base             |  musl libc  |  linux   | loongarch64-unknown-linux-musl|
-|           lp64f/base             |  musl libc  |  linux   | loongarch64-unknown-linux-muslf32|
-|           lp64s/base             |  musl libc  |  linux   | loongarch64-unknown-linux-muslsf |
+[la-abi-specs]: https://github.com/loongson/la-abi-specs
+[la-docs]: https://loongson.github.io/LoongArch-Documentation/README-EN.html
 
 ## Target maintainers
 
@@ -35,23 +29,57 @@ While the integer base ABI is implied by the machine field, the floating po
 
 ## Requirements
 
-This target is cross-compiled.
-A GNU toolchain for LoongArch target is required.  It can be downloaded from https://github.com/loongson/build-tools/releases, or built from the source code of GCC (12.1.0 or later) and Binutils (2.40 or later).
+### OS Version
 
-## Building the target
+The minimum supported Linux version is 5.19.
 
-The target can be built by enabling it for a `rustc` build.
+Some Linux distributions, mostly commercial ones, may provide forked Linux
+kernels that has a version number less than 5.19 for their LoongArch ports.
+Such kernels may still get patched to be compatible with the upstream Linux
+5.19 UAPI, therefore supporting the targets described in this document, but
+this is not always the case. The `rustup` installer contains a check for this,
+and will abort if incompatibility is detected.
+
+### Host toolchain
+
+The targets require a reasonably up-to-date LoongArch toolchain on the host.
+Currently the following components are used by the Rust CI to build the target,
+and the versions can be seen as the minimum requirement:
+
+* GNU Binutils 2.40
+* GCC 13.x
+* glibc 2.36
+* linux-headers 5.19
+
+Of these, glibc and linux-headers are at their respective earliest versions with
+mainline LoongArch support, so it is impossible to use older versions of these.
+Older versions of Binutils and GCC will not work either, due to lack of support
+for newer LoongArch ELF relocation types, among other features.
+
+Recent LLVM/Clang toolchains may be able to build the targets, but are not
+currently being actively tested.
+
+## Building
+
+These targets are distributed through `rustup`, and otherwise require no
+special configuration.
+
+If you need to build your own Rust for some reason though, the targets can be
+simply enabled in `config.toml`. For example:
 
 ```toml
 [build]
 target = ["loongarch64-unknown-linux-gnu"]
 ```
 
-Make sure `loongarch64-unknown-linux-gnu-gcc` can be searched from the directories specified in`$PATH`. Alternatively, you can use GNU LoongArch Toolchain by adding the following to `config.toml`:
+Make sure the LoongArch toolchain binaries are reachable from `$PATH`.
+Alternatively, you can explicitly configure the paths in `config.toml`:
 
 ```toml
 [target.loongarch64-unknown-linux-gnu]
-# ADJUST THIS PATH TO POINT AT YOUR TOOLCHAIN
+# Adjust the paths to point at your toolchain
+# Suppose the toolchain is placed at /TOOLCHAIN_PATH, and the cross prefix is
+# "loongarch64-unknown-linux-gnu-":
 cc = "/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-gcc"
 cxx = "/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-g++"
 ar = "/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-ar"
@@ -59,36 +87,51 @@ ranlib = "/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-ranlib"
 linker = "/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-gcc"
 ```
 
-## Cross-compilation
+### Cross-compilation
 
-This target can be cross-compiled on a `x86_64-unknown-linux-gnu` host. Cross-compilation on other hosts may work but is not tested.
+This target can be cross-compiled on a `x86_64-unknown-linux-gnu` host.
+Other hosts are also likely to work, but not actively tested.
+
+You can test the cross build directly on the host, thanks to QEMU linux-user emulation.
+An example is given below:
+
+```sh
+# Suppose the cross toolchain is placed at $TOOLCHAIN_PATH, with a cross prefix
+# of "loongarch64-unknown-linux-gnu-".
+export CC_loongarch64_unknown_linux_gnu="$TOOLCHAIN_PATH"/bin/loongarch64-unknown-linux-gnu-gcc
+export CXX_loongarch64_unknown_linux_gnu="$TOOLCHAIN_PATH"/bin/loongarch64-unknown-linux-gnu-g++
+export AR_loongarch64_unknown_linux_gnu="$TOOLCHAIN_PATH"/bin/loongarch64-unknown-linux-gnu-gcc-ar
+export CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PATH"/bin/loongarch64-unknown-linux-gnu-gcc
+
+# Point qemu-loongarch64 to the LoongArch sysroot.
+# Suppose the sysroot is located at "sysroot" below the toolchain root:
+export CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNU_RUNNER="qemu-loongarch64 -L $TOOLCHAIN_PATH/sysroot"
+# Or alternatively, if binfmt_misc is set up for running LoongArch binaries
+# transparently:
+export QEMU_LD_PREFIX="$TOOLCHAIN_PATH"/sysroot
 
-## Testing
-To test a cross-compiled binary on your build system, install the qemu binary that supports the LoongArch architecture and execute the following commands.
-```text
-CC_loongarch64_unknown_linux_gnu=/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-gcc \
-CXX_loongarch64_unknown_linux_gnu=/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-g++ \
-AR_loongarch64_unknown_linux_gnu=/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-gcc-ar \
-CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNUN_LINKER=/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-gcc \
-# SET TARGET SYSTEM LIBRARY PATH
-CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNUN_RUNNER="qemu-loongarch64 -L /TOOLCHAIN_PATH/TARGET_LIBRARY_PATH" \
 cargo run --target loongarch64-unknown-linux-gnu --release
 ```
-Tested on x86 architecture, other architectures not tested.
 
-## Building Rust programs
+## Testing
+
+There are no special requirements for testing and running the targets.
+For testing cross builds on the host, please refer to the "Cross-compilation"
+section above.
 
-Rust does not yet ship pre-compiled artifacts for this target. To compile for this target, you will either need to build Rust with the target enabled (see "Building the target" above), or build your own copy of `std` by using `build-std` or similar.
+## Building Rust programs
 
-If `rustc` has support for that target and the library artifacts are available, then Rust static libraries can be built for that target:
+As the targets are available through `rustup`, it is very easy to build Rust
+programs for these targets: same as with other architectures.
+Note that you will need a LoongArch C/C++ toolchain for linking, or if you want
+to compile C code along with Rust (such as for Rust crates with C dependencies).
 
-```shell
-$ rustc --target loongarch64-unknown-linux-gnu your-code.rs --crate-type staticlib
-$ ls libyour_code.a
+```sh
+rustup target add loongarch64-unknown-linux-gnu
+cargo build --target loongarch64-unknown-linux-gnu
 ```
 
-On Rust Nightly it's possible to build without the target artifacts available:
+Availability of pre-built artifacts through `rustup` are as follows:
 
-```text
-cargo build -Z build-std --target loongarch64-unknown-linux-gnu
-```
+* `loongarch64-unknown-linux-gnu`: since Rust 1.71;
+* `loongarch64-unknown-linux-musl`: since Rust 1.81.
diff --git a/src/doc/rustc/src/platform-support/loongarch-none.md b/src/doc/rustc/src/platform-support/loongarch-none.md
index 68d7c9d85e4..110a7cc3424 100644
--- a/src/doc/rustc/src/platform-support/loongarch-none.md
+++ b/src/doc/rustc/src/platform-support/loongarch-none.md
@@ -4,10 +4,10 @@
 
 Freestanding/bare-metal LoongArch64 binaries in ELF format: firmware, kernels, etc.
 
-| Target                             | Descriptions                                          |
-|------------------------------------|-------------------------------------------------------|
-| loongarch64-unknown-none           | LoongArch 64-bit, LP64D ABI (freestanding, hardfloat) |
-| loongarch64-unknown-none-softfloat | LoongArch 64-bit, LP64S ABI (freestanding, softfloat) |
+| Target | Description |
+|--------|-------------|
+| `loongarch64-unknown-none` | LoongArch 64-bit, LP64D ABI (freestanding, hard-float) |
+| `loongarch64-unknown-none-softfloat` | LoongArch 64-bit, LP64S ABI (freestanding, soft-float) |
 
 ## Target maintainers
 
@@ -19,6 +19,8 @@ Freestanding/bare-metal LoongArch64 binaries in ELF format: firmware, kernels, e
 This target is cross-compiled. There is no support for `std`. There is no
 default allocator, but it's possible to use `alloc` by supplying an allocator.
 
+The `*-softfloat` target does not assume existence of FPU or any other LoongArch
+ISA extension, and does not make use of any non-GPR register.
 This allows the generated code to run in environments, such as kernels, which
 may need to avoid the use of such registers or which may have special considerations
 about the use of such registers (e.g. saving and restoring them to avoid breaking
@@ -26,54 +28,64 @@ userspace code using the same registers). You can change code generation to use
 additional CPU features via the `-C target-feature=` codegen options to rustc, or
 via the `#[target_feature]` mechanism within Rust code.
 
-By default, code generated with this target should run on any `loongarch`
-hardware; enabling additional target features may raise this baseline.
+By default, code generated with the soft-float target should run on any
+LoongArch64 hardware, with the hard-float target additionally requiring an FPU;
+enabling additional target features may raise this baseline.
 
-Code generated with this target will use the `small` code model by default.
+Code generated with the targets will use the `small` code model by default.
 You can change this using the `-C code-model=` option to rustc.
 
-On `loongarch64-unknown-none*`, `extern "C"` uses the [standard calling
-convention](https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html).
+On `loongarch64-unknown-none*`, `extern "C"` uses the [architecture's standard calling convention][lapcs].
 
-This target generates binaries in the ELF format. Any alternate formats or
+[lapcs]: https://github.com/loongson/la-abi-specs/blob/release/lapcs.adoc
+
+The targets generate binaries in the ELF format. Any alternate formats or
 special considerations for binary layout will require linker options or linker
 scripts.
 
 ## Building the target
 
-You can build Rust with support for the target by adding it to the `target`
+You can build Rust with support for the targets by adding them to the `target`
 list in `config.toml`:
 
 ```toml
 [build]
 build-stage = 1
-target = ["loongarch64-unknown-none"]
+target = [
+  "loongarch64-unknown-none",
+  "loongarch64-unknown-none-softfloat",
+]
 ```
 
+## Testing
+
+As the targets support a variety of different environments and do not support
+`std`, they do not support running the Rust test suite.
+
 ## Building Rust programs
 
-```text
+Starting with Rust 1.74, precompiled artifacts are provided via `rustup`:
+
+```sh
+# install cross-compile toolchain
+rustup target add loongarch64-unknown-none
 # target flag may be used with any cargo or rustc command
 cargo build --target loongarch64-unknown-none
 ```
 
-## Testing
-
-As `loongarch64-unknown-none*` supports a variety of different environments and does
-not support `std`, this target does not support running the Rust test suite.
-
 ## Cross-compilation toolchains and C code
 
-If you want to compile C code along with Rust (such as for Rust crates with C
-dependencies), you will need an appropriate `loongarch` toolchain.
+For cross builds, you will need an appropriate LoongArch C/C++ toolchain for
+linking, or if you want to compile C code along with Rust (such as for Rust
+crates with C dependencies).
 
 Rust *may* be able to use an `loongarch64-unknown-linux-gnu-` toolchain with
 appropriate standalone flags to build for this toolchain (depending on the assumptions
 of that toolchain, see below), or you may wish to use a separate
 `loongarch64-unknown-none` toolchain.
 
-On some `loongarch` hosts that use ELF binaries, you *may* be able to use the host
+On some LoongArch hosts that use ELF binaries, you *may* be able to use the host
 C toolchain, if it does not introduce assumptions about the host environment
 that don't match the expectations of a standalone environment. Otherwise, you
 may need a separate toolchain for standalone/freestanding development, just as
-when cross-compiling from a non-`loongarch` platform.
+when cross-compiling from a non-LoongArch platform.
diff --git a/src/doc/rustc/src/platform-support/powerpc-unknown-openbsd.md b/src/doc/rustc/src/platform-support/powerpc-unknown-openbsd.md
new file mode 100644
index 00000000000..b1600c71f1f
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/powerpc-unknown-openbsd.md
@@ -0,0 +1,3 @@
+## Designated maintainers
+
+`powerpc-unknown-openbsd` is not maintained by OpenBSD developers and there are currently no active rustc maintainers.
diff --git a/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md b/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md
index 2b3d15e93c8..c3eda26ca8e 100644
--- a/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md
+++ b/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md
@@ -107,7 +107,7 @@ flag, for example:
 
 Users need to install or built wasi-sdk since release 20.0
 https://github.com/WebAssembly/wasi-sdk/releases/tag/wasi-sdk-20
-and specify path to *wasi-root* `.cargo/config.toml`
+and specify path to *wasi-root* `config.toml`
 
 ```toml
 [target.wasm32-wasip1-threads]
diff --git a/src/doc/rustc/src/platform-support/xtensa.md b/src/doc/rustc/src/platform-support/xtensa.md
index 7785977466e..332b8ee9c15 100644
--- a/src/doc/rustc/src/platform-support/xtensa.md
+++ b/src/doc/rustc/src/platform-support/xtensa.md
@@ -1,4 +1,4 @@
-# `xtensa-*`
+# `xtensa-*-none-elf`
 
 **Tier: 3**
 
@@ -20,6 +20,8 @@ The target names follow this format: `xtensa-$CPU`, where `$CPU` specifies the t
 | `xtensa-esp32s3-none-elf` | [ESP32-S3](https://www.espressif.com/en/products/socs/esp32-s3) |
 
 
-## Building the target
+Xtensa targets that support `std` are documented in the [ESP-IDF platform support document](esp-idf.md)
+
+## 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).
diff --git a/src/doc/rustdoc/src/advanced-features.md b/src/doc/rustdoc/src/advanced-features.md
index 1733c8fc9a2..4a1c0916253 100644
--- a/src/doc/rustdoc/src/advanced-features.md
+++ b/src/doc/rustdoc/src/advanced-features.md
@@ -80,7 +80,8 @@ pub struct BigX;
 Then, when looking for it through the `rustdoc` search, if you enter "x" or
 "big", search will show the `BigX` struct first.
 
-There are some limitations on the doc alias names though: you can't use `"` or whitespace.
+There are some limitations on the doc alias names though: they cannot contain quotes (`'`, `"`)
+or most whitespace. ASCII space is allowed if it does not start or end the alias.
 
 You can add multiple aliases at the same time by using a list:
 
diff --git a/src/doc/style-guide/src/nightly.md b/src/doc/style-guide/src/nightly.md
index 66e7fa3c9f8..d870edf1888 100644
--- a/src/doc/style-guide/src/nightly.md
+++ b/src/doc/style-guide/src/nightly.md
@@ -5,3 +5,15 @@ 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/unstable-book/src/compiler-flags/patchable-function-entry.md b/src/doc/unstable-book/src/compiler-flags/patchable-function-entry.md
new file mode 100644
index 00000000000..4a9bf47a290
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/patchable-function-entry.md
@@ -0,0 +1,24 @@
+# `patchable-function-entry`
+
+--------------------
+
+The `-Z patchable-function-entry=total_nops,prefix_nops` or `-Z patchable-function-entry=total_nops`
+compiler flag enables nop padding of function entries with 'total_nops' nops, with
+an offset for the entry of the function at 'prefix_nops' nops. In the second form,
+'prefix_nops' defaults to 0.
+
+As an illustrative example, `-Z patchable-function-entry=3,2` would produce:
+
+```text
+nop
+nop
+function_label:
+nop
+//Actual function code begins here
+```
+
+This flag is used for hotpatching, especially in the Linux kernel. The flag
+arguments are modeled after the `-fpatchable-function-entry` flag as defined
+for both [Clang](https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fpatchable-function-entry)
+and [gcc](https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html#index-fpatchable-function-entry)
+and is intended to provide the same effect.
diff --git a/src/doc/unstable-book/src/compiler-flags/verbose-asm.md b/src/doc/unstable-book/src/compiler-flags/verbose-asm.md
new file mode 100644
index 00000000000..84eb90a14cf
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/verbose-asm.md
@@ -0,0 +1,70 @@
+# `verbose-asm`
+
+The tracking issue for this feature is: [#126802](https://github.com/rust-lang/rust/issues/126802).
+
+------------------------
+
+This enables passing `-Zverbose-asm` to get contextual comments added by LLVM.
+
+Sample code:
+
+```rust
+#[no_mangle]
+pub fn foo(a: i32, b: i32) -> i32 {
+    a + b
+}
+```
+
+Default output:
+
+```asm
+foo:
+        push    rax
+        add     edi, esi
+        mov     dword ptr [rsp + 4], edi
+        seto    al
+        jo      .LBB0_2
+        mov     eax, dword ptr [rsp + 4]
+        pop     rcx
+        ret
+.LBB0_2:
+        lea     rdi, [rip + .L__unnamed_1]
+        mov     rax, qword ptr [rip + core::panicking::panic_const::panic_const_add_overflow::h9c85248fe0d735b2@GOTPCREL]
+        call    rax
+
+.L__unnamed_2:
+        .ascii  "/app/example.rs"
+
+.L__unnamed_1:
+        .quad   .L__unnamed_2
+        .asciz  "\017\000\000\000\000\000\000\000\004\000\000\000\005\000\000"
+```
+
+With `-Zverbose-asm`:
+
+```asm
+foo:                                    # @foo
+# %bb.0:
+        push    rax
+        add     edi, esi
+        mov     dword ptr [rsp + 4], edi        # 4-byte Spill
+        seto    al
+        jo      .LBB0_2
+# %bb.1:
+        mov     eax, dword ptr [rsp + 4]        # 4-byte Reload
+        pop     rcx
+        ret
+.LBB0_2:
+        lea     rdi, [rip + .L__unnamed_1]
+        mov     rax, qword ptr [rip + core::panicking::panic_const::panic_const_add_overflow::h9c85248fe0d735b2@GOTPCREL]
+        call    rax
+                                        # -- End function
+.L__unnamed_2:
+        .ascii  "/app/example.rs"
+
+.L__unnamed_1:
+        .quad   .L__unnamed_2
+        .asciz  "\017\000\000\000\000\000\000\000\004\000\000\000\005\000\000"
+
+                                        # DW_AT_external
+```
diff --git a/src/doc/unstable-book/src/language-features/c-unwind.md b/src/doc/unstable-book/src/language-features/c-unwind.md
deleted file mode 100644
index fb32918d5e4..00000000000
--- a/src/doc/unstable-book/src/language-features/c-unwind.md
+++ /dev/null
@@ -1,26 +0,0 @@
-# `c_unwind`
-
-The tracking issue for this feature is: [#74990]
-
-[#74990]: https://github.com/rust-lang/rust/issues/74990
-
-------------------------
-
-Introduces new ABI strings:
-- "C-unwind"
-- "cdecl-unwind"
-- "stdcall-unwind"
-- "fastcall-unwind"
-- "vectorcall-unwind"
-- "thiscall-unwind"
-- "aapcs-unwind"
-- "win64-unwind"
-- "sysv64-unwind"
-- "system-unwind"
-
-These enable unwinding from other languages (such as C++) into Rust frames and
-from Rust into other languages.
-
-See [RFC 2945] for more information.
-
-[RFC 2945]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md
diff --git a/src/doc/unstable-book/src/language-features/intrinsics.md b/src/doc/unstable-book/src/language-features/intrinsics.md
index 02a009d56d3..c262d3f6da1 100644
--- a/src/doc/unstable-book/src/language-features/intrinsics.md
+++ b/src/doc/unstable-book/src/language-features/intrinsics.md
@@ -18,7 +18,7 @@ All intrinsic fallback bodies are automatically made cross-crate inlineable (lik
 by the codegen backend, but not the MIR inliner.
 
 ```rust
-#![feature(rustc_attrs, effects)]
+#![feature(rustc_attrs)]
 #![allow(internal_features)]
 
 #[rustc_intrinsic]
@@ -28,7 +28,7 @@ const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {}
 Since these are just regular functions, it is perfectly ok to create the intrinsic twice:
 
 ```rust
-#![feature(rustc_attrs, effects)]
+#![feature(rustc_attrs)]
 #![allow(internal_features)]
 
 #[rustc_intrinsic]
diff --git a/src/doc/unstable-book/src/library-features/sort-internals.md b/src/doc/unstable-book/src/library-features/sort-internals.md
deleted file mode 100644
index 6f2385e5300..00000000000
--- a/src/doc/unstable-book/src/library-features/sort-internals.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# `sort_internals`
-
-This feature is internal to the Rust compiler and is not intended for general use.
-
-------------------------
diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish
index 7343f3147ee..805fc8aa8cc 100644
--- a/src/etc/completions/x.py.fish
+++ b/src/etc/completions/x.py.fish
@@ -48,6 +48,7 @@ complete -c x.py -n "__fish_use_subcommand" -f -a "run" -d 'Run tools contained
 complete -c x.py -n "__fish_use_subcommand" -f -a "setup" -d 'Set up the environment for development'
 complete -c x.py -n "__fish_use_subcommand" -f -a "suggest" -d 'Suggest a subset of tests to run, based on modified files'
 complete -c x.py -n "__fish_use_subcommand" -f -a "vendor" -d 'Vendor dependencies'
+complete -c x.py -n "__fish_use_subcommand" -f -a "perf" -d 'Perform profiling and benchmarking of the compiler using the `rustc-perf-wrapper` tool'
 complete -c x.py -n "__fish_seen_subcommand_from build" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from build" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)"
 complete -c x.py -n "__fish_seen_subcommand_from build" -l build -d 'build target of the stage0 compiler' -r -f
@@ -628,3 +629,37 @@ complete -c x.py -n "__fish_seen_subcommand_from vendor" -l llvm-profile-generat
 complete -c x.py -n "__fish_seen_subcommand_from vendor" -l enable-bolt-settings -d 'Enable BOLT link flags'
 complete -c x.py -n "__fish_seen_subcommand_from vendor" -l skip-stage0-validation -d 'Skip stage0 compiler validation'
 complete -c x.py -n "__fish_seen_subcommand_from vendor" -s h -l help -d 'Print help (see more with \'--help\')'
+complete -c x.py -n "__fish_seen_subcommand_from perf" -l config -d 'TOML configuration file for build' -r -F
+complete -c x.py -n "__fish_seen_subcommand_from perf" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)"
+complete -c x.py -n "__fish_seen_subcommand_from perf" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x.py -n "__fish_seen_subcommand_from perf" -l host -d 'host targets to build' -r -f
+complete -c x.py -n "__fish_seen_subcommand_from perf" -l target -d 'target targets to build' -r -f
+complete -c x.py -n "__fish_seen_subcommand_from perf" -l exclude -d 'build paths to exclude' -r -F
+complete -c x.py -n "__fish_seen_subcommand_from perf" -l skip -d 'build paths to skip' -r -F
+complete -c x.py -n "__fish_seen_subcommand_from perf" -l rustc-error-format -r -f
+complete -c x.py -n "__fish_seen_subcommand_from perf" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)"
+complete -c x.py -n "__fish_seen_subcommand_from perf" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f
+complete -c x.py -n "__fish_seen_subcommand_from perf" -l keep-stage -d 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f
+complete -c x.py -n "__fish_seen_subcommand_from perf" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f
+complete -c x.py -n "__fish_seen_subcommand_from perf" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)"
+complete -c x.py -n "__fish_seen_subcommand_from perf" -s j -l jobs -d 'number of jobs to run in parallel' -r -f
+complete -c x.py -n "__fish_seen_subcommand_from perf" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny	'',warn	'',default	''}"
+complete -c x.py -n "__fish_seen_subcommand_from perf" -l error-format -d 'rustc error format' -r -f
+complete -c x.py -n "__fish_seen_subcommand_from perf" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always	'',never	'',auto	''}"
+complete -c x.py -n "__fish_seen_subcommand_from perf" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true	'',false	''}"
+complete -c x.py -n "__fish_seen_subcommand_from perf" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F
+complete -c x.py -n "__fish_seen_subcommand_from perf" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F
+complete -c x.py -n "__fish_seen_subcommand_from perf" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F
+complete -c x.py -n "__fish_seen_subcommand_from perf" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r
+complete -c x.py -n "__fish_seen_subcommand_from perf" -l set -d 'override options in config.toml' -r -f
+complete -c x.py -n "__fish_seen_subcommand_from perf" -s v -l verbose -d 'use verbose output (-vv for very verbose)'
+complete -c x.py -n "__fish_seen_subcommand_from perf" -s i -l incremental -d 'use incremental compilation'
+complete -c x.py -n "__fish_seen_subcommand_from perf" -l include-default-paths -d 'include default paths in addition to the provided ones'
+complete -c x.py -n "__fish_seen_subcommand_from perf" -l dry-run -d 'dry run; don\'t build anything'
+complete -c x.py -n "__fish_seen_subcommand_from perf" -l dump-bootstrap-shims -d 'Indicates whether to dump the work done from bootstrap shims'
+complete -c x.py -n "__fish_seen_subcommand_from perf" -l json-output -d 'use message-format=json'
+complete -c x.py -n "__fish_seen_subcommand_from perf" -l bypass-bootstrap-lock -d 'Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)'
+complete -c x.py -n "__fish_seen_subcommand_from perf" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc'
+complete -c x.py -n "__fish_seen_subcommand_from perf" -l enable-bolt-settings -d 'Enable BOLT link flags'
+complete -c x.py -n "__fish_seen_subcommand_from perf" -l skip-stage0-validation -d 'Skip stage0 compiler validation'
+complete -c x.py -n "__fish_seen_subcommand_from perf" -s h -l help -d 'Print help (see more with \'--help\')'
diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1
index d9adb1778f2..ce590d2fa48 100644
--- a/src/etc/completions/x.py.ps1
+++ b/src/etc/completions/x.py.ps1
@@ -75,6 +75,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('setup', 'setup', [CompletionResultType]::ParameterValue, 'Set up the environment for development')
             [CompletionResult]::new('suggest', 'suggest', [CompletionResultType]::ParameterValue, 'Suggest a subset of tests to run, based on modified files')
             [CompletionResult]::new('vendor', 'vendor', [CompletionResultType]::ParameterValue, 'Vendor dependencies')
+            [CompletionResult]::new('perf', 'perf', [CompletionResultType]::ParameterValue, 'Perform profiling and benchmarking of the compiler using the `rustc-perf-wrapper` tool')
             break
         }
         'x.py;build' {
@@ -769,6 +770,47 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
             break
         }
+        'x.py;perf' {
+            [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
+            [CompletionResult]::new('--build-dir', 'build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `config.toml`')
+            [CompletionResult]::new('--build', 'build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--host', 'host', [CompletionResultType]::ParameterName, 'host targets to build')
+            [CompletionResult]::new('--target', 'target', [CompletionResultType]::ParameterName, 'target targets to build')
+            [CompletionResult]::new('--exclude', 'exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
+            [CompletionResult]::new('--skip', 'skip', [CompletionResultType]::ParameterName, 'build paths to skip')
+            [CompletionResult]::new('--rustc-error-format', 'rustc-error-format', [CompletionResultType]::ParameterName, 'rustc-error-format')
+            [CompletionResult]::new('--on-fail', 'on-fail', [CompletionResultType]::ParameterName, 'command to run on failure')
+            [CompletionResult]::new('--stage', 'stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)')
+            [CompletionResult]::new('--keep-stage', 'keep-stage', [CompletionResultType]::ParameterName, 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)')
+            [CompletionResult]::new('--keep-stage-std', 'keep-stage-std', [CompletionResultType]::ParameterName, 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)')
+            [CompletionResult]::new('--src', 'src', [CompletionResultType]::ParameterName, 'path to the root of the rust checkout')
+            [CompletionResult]::new('-j', 'j', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel')
+            [CompletionResult]::new('--jobs', 'jobs', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel')
+            [CompletionResult]::new('--warnings', 'warnings', [CompletionResultType]::ParameterName, 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour')
+            [CompletionResult]::new('--error-format', 'error-format', [CompletionResultType]::ParameterName, 'rustc error format')
+            [CompletionResult]::new('--color', 'color', [CompletionResultType]::ParameterName, 'whether to use color in cargo and rustc output')
+            [CompletionResult]::new('--llvm-skip-rebuild', 'llvm-skip-rebuild', [CompletionResultType]::ParameterName, 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml')
+            [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build')
+            [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build')
+            [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build')
+            [CompletionResult]::new('--reproducible-artifact', 'reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive')
+            [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml')
+            [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
+            [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
+            [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'use incremental compilation')
+            [CompletionResult]::new('--incremental', 'incremental', [CompletionResultType]::ParameterName, 'use incremental compilation')
+            [CompletionResult]::new('--include-default-paths', 'include-default-paths', [CompletionResultType]::ParameterName, 'include default paths in addition to the provided ones')
+            [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything')
+            [CompletionResult]::new('--dump-bootstrap-shims', 'dump-bootstrap-shims', [CompletionResultType]::ParameterName, 'Indicates whether to dump the work done from bootstrap shims')
+            [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json')
+            [CompletionResult]::new('--bypass-bootstrap-lock', 'bypass-bootstrap-lock', [CompletionResultType]::ParameterName, 'Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)')
+            [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc')
+            [CompletionResult]::new('--enable-bolt-settings', 'enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags')
+            [CompletionResult]::new('--skip-stage0-validation', 'skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation')
+            [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
+            [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
+            break
+        }
     })
 
     $completions.Where{ $_.CompletionText -like "$wordToComplete*" } |
diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh
index 6cb9e95c8c1..a4234905476 100644
--- a/src/etc/completions/x.py.sh
+++ b/src/etc/completions/x.py.sh
@@ -45,6 +45,9 @@ _x.py() {
             bootstrap,miri)
                 cmd="bootstrap__miri"
                 ;;
+            bootstrap,perf)
+                cmd="bootstrap__perf"
+                ;;
             bootstrap,run)
                 cmd="bootstrap__run"
                 ;;
@@ -67,7 +70,7 @@ _x.py() {
 
     case "${cmd}" in
         x.py)
-            opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]... build check clippy fix fmt doc test miri bench clean dist install run setup suggest vendor"
+            opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]... build check clippy fix fmt doc test miri bench clean dist install run setup suggest vendor perf"
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
@@ -1414,6 +1417,116 @@ _x.py() {
             COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
             return 0
             ;;
+        x.py__perf)
+            opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]..."
+            if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
+                COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
+                return 0
+            fi
+            case "${prev}" in
+                --config)
+                    COMPREPLY=($(compgen -f "${cur}"))
+                    return 0
+                    ;;
+                --build-dir)
+                    COMPREPLY=($(compgen -f "${cur}"))
+                    return 0
+                    ;;
+                --build)
+                    COMPREPLY=("${cur}")
+                    return 0
+                    ;;
+                --host)
+                    COMPREPLY=("${cur}")
+                    return 0
+                    ;;
+                --target)
+                    COMPREPLY=("${cur}")
+                    return 0
+                    ;;
+                --exclude)
+                    COMPREPLY=($(compgen -f "${cur}"))
+                    return 0
+                    ;;
+                --skip)
+                    COMPREPLY=($(compgen -f "${cur}"))
+                    return 0
+                    ;;
+                --rustc-error-format)
+                    COMPREPLY=("${cur}")
+                    return 0
+                    ;;
+                --on-fail)
+                    COMPREPLY=($(compgen -f "${cur}"))
+                    return 0
+                    ;;
+                --stage)
+                    COMPREPLY=("${cur}")
+                    return 0
+                    ;;
+                --keep-stage)
+                    COMPREPLY=("${cur}")
+                    return 0
+                    ;;
+                --keep-stage-std)
+                    COMPREPLY=("${cur}")
+                    return 0
+                    ;;
+                --src)
+                    COMPREPLY=($(compgen -f "${cur}"))
+                    return 0
+                    ;;
+                --jobs)
+                    COMPREPLY=("${cur}")
+                    return 0
+                    ;;
+                -j)
+                    COMPREPLY=("${cur}")
+                    return 0
+                    ;;
+                --warnings)
+                    COMPREPLY=($(compgen -W "deny warn default" -- "${cur}"))
+                    return 0
+                    ;;
+                --error-format)
+                    COMPREPLY=("${cur}")
+                    return 0
+                    ;;
+                --color)
+                    COMPREPLY=($(compgen -W "always never auto" -- "${cur}"))
+                    return 0
+                    ;;
+                --llvm-skip-rebuild)
+                    COMPREPLY=($(compgen -W "true false" -- "${cur}"))
+                    return 0
+                    ;;
+                --rust-profile-generate)
+                    COMPREPLY=($(compgen -f "${cur}"))
+                    return 0
+                    ;;
+                --rust-profile-use)
+                    COMPREPLY=($(compgen -f "${cur}"))
+                    return 0
+                    ;;
+                --llvm-profile-use)
+                    COMPREPLY=($(compgen -f "${cur}"))
+                    return 0
+                    ;;
+                --reproducible-artifact)
+                    COMPREPLY=($(compgen -f "${cur}"))
+                    return 0
+                    ;;
+                --set)
+                    COMPREPLY=("${cur}")
+                    return 0
+                    ;;
+                *)
+                    COMPREPLY=()
+                    ;;
+            esac
+            COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
+            return 0
+            ;;
         x.py__run)
             opts="-v -i -j -h --args --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]..."
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh
index 24ddd1c4b7c..fc8be4f7881 100644
--- a/src/etc/completions/x.py.zsh
+++ b/src/etc/completions/x.py.zsh
@@ -789,6 +789,49 @@ _arguments "${_arguments_options[@]}" \
 '*::paths -- paths for the subcommand:_files' \
 && ret=0
 ;;
+(perf)
+_arguments "${_arguments_options[@]}" \
+'--config=[TOML configuration file for build]:FILE:_files' \
+'--build-dir=[Build directory, overrides \`build.build-dir\` in \`config.toml\`]:DIR:_files -/' \
+'--build=[build target of the stage0 compiler]:BUILD:( )' \
+'--host=[host targets to build]:HOST:( )' \
+'--target=[target targets to build]:TARGET:( )' \
+'*--exclude=[build paths to exclude]:PATH:_files' \
+'*--skip=[build paths to skip]:PATH:_files' \
+'--rustc-error-format=[]:RUSTC_ERROR_FORMAT:( )' \
+'--on-fail=[command to run on failure]:CMD:_cmdstring' \
+'--stage=[stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)]:N:( )' \
+'*--keep-stage=[stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \
+'*--keep-stage-std=[stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \
+'--src=[path to the root of the rust checkout]:DIR:_files -/' \
+'-j+[number of jobs to run in parallel]:JOBS:( )' \
+'--jobs=[number of jobs to run in parallel]:JOBS:( )' \
+'--warnings=[if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour]:deny|warn:(deny warn default)' \
+'--error-format=[rustc error format]:FORMAT:( )' \
+'--color=[whether to use color in cargo and rustc output]:STYLE:(always never auto)' \
+'--llvm-skip-rebuild=[whether rebuilding llvm should be skipped, overriding \`skip-rebuld\` in config.toml]:VALUE:(true false)' \
+'--rust-profile-generate=[generate PGO profile with rustc build]:PROFILE:_files' \
+'--rust-profile-use=[use PGO profile for rustc build]:PROFILE:_files' \
+'--llvm-profile-use=[use PGO profile for LLVM build]:PROFILE:_files' \
+'*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT: ' \
+'*--set=[override options in config.toml]:section.option=value:( )' \
+'*-v[use verbose output (-vv for very verbose)]' \
+'*--verbose[use verbose output (-vv for very verbose)]' \
+'-i[use incremental compilation]' \
+'--incremental[use incremental compilation]' \
+'--include-default-paths[include default paths in addition to the provided ones]' \
+'--dry-run[dry run; don'\''t build anything]' \
+'--dump-bootstrap-shims[Indicates whether to dump the work done from bootstrap shims]' \
+'--json-output[use message-format=json]' \
+'--bypass-bootstrap-lock[Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)]' \
+'--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \
+'--enable-bolt-settings[Enable BOLT link flags]' \
+'--skip-stage0-validation[Skip stage0 compiler validation]' \
+'-h[Print help (see more with '\''--help'\'')]' \
+'--help[Print help (see more with '\''--help'\'')]' \
+'*::paths -- paths for the subcommand:_files' \
+&& ret=0
+;;
         esac
     ;;
 esac
@@ -813,6 +856,7 @@ _x.py_commands() {
 'setup:Set up the environment for development' \
 'suggest:Suggest a subset of tests to run, based on modified files' \
 'vendor:Vendor dependencies' \
+'perf:Perform profiling and benchmarking of the compiler using the \`rustc-perf-wrapper\` tool' \
     )
     _describe -t commands 'x.py commands' commands "$@"
 }
@@ -871,6 +915,11 @@ _x.py__miri_commands() {
     local commands; commands=()
     _describe -t commands 'x.py miri commands' commands "$@"
 }
+(( $+functions[_x.py__perf_commands] )) ||
+_x.py__perf_commands() {
+    local commands; commands=()
+    _describe -t commands 'x.py perf commands' commands "$@"
+}
 (( $+functions[_x.py__run_commands] )) ||
 _x.py__run_commands() {
     local commands; commands=()
diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py
index 2e0f832192f..3d7ead99282 100755
--- a/src/etc/htmldocck.py
+++ b/src/etc/htmldocck.py
@@ -240,9 +240,37 @@ def concat_multi_lines(f):
         print_err(lineno, line, 'Trailing backslash at the end of the file')
 
 
+def get_known_directive_names():
+    def filter_line(line):
+        line = line.strip()
+        return line.startswith('"') and (line.endswith('",') or line.endswith('"'))
+
+    # Equivalent to `src/tools/compiletest/src/header.rs` constant of the same name.
+    with open(
+        os.path.join(
+            # We go back to `src`.
+            os.path.dirname(os.path.dirname(__file__)),
+            "tools/compiletest/src/command-list.rs",
+        ),
+        "r",
+        encoding="utf8"
+    ) as fd:
+        content = fd.read()
+        return [
+            line.strip().replace('",', '').replace('"', '')
+            for line in content.split('\n')
+            if filter_line(line)
+        ]
+
+
+# To prevent duplicating the list of commmands between `compiletest` and `htmldocck`, we put
+# it into a common file which is included in rust code and parsed here.
+# FIXME: This setup is temporary until we figure out how to improve this situation.
+KNOWN_DIRECTIVE_NAMES = get_known_directive_names()
+
 LINE_PATTERN = re.compile(r'''
-    (?<=(?<!\S))(?P<invalid>!?)@(?P<negated>!?)
-    (?P<cmd>[A-Za-z]+(?:-[A-Za-z]+)*)
+    //@\s+
+    (?P<negated>!?)(?P<cmd>[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*)
     (?P<args>.*)$
 ''', re.X | re.UNICODE)
 
@@ -254,17 +282,9 @@ def get_commands(template):
             if not m:
                 continue
 
-            negated = (m.group('negated') == '!')
             cmd = m.group('cmd')
-            if m.group('invalid') == '!':
-                print_err(
-                    lineno,
-                    line,
-                    'Invalid command: `!@{0}{1}`, (help: try with `@!{1}`)'.format(
-                        '!' if negated else '',
-                        cmd,
-                    ),
-                )
+            negated = (m.group('negated') == '!')
+            if not negated and cmd in KNOWN_DIRECTIVE_NAMES:
                 continue
             args = m.group('args')
             if args and not args[:1].isspace():
@@ -549,7 +569,7 @@ def get_nb_matching_elements(cache, c, regexp, stop_at_first):
 def check_files_in_folder(c, cache, folder, files):
     files = files.strip()
     if not files.startswith('[') or not files.endswith(']'):
-        raise InvalidCheck("Expected list as second argument of @{} (ie '[]')".format(c.cmd))
+        raise InvalidCheck("Expected list as second argument of {} (ie '[]')".format(c.cmd))
 
     folder = cache.get_absolute_path(folder)
 
@@ -558,7 +578,7 @@ def check_files_in_folder(c, cache, folder, files):
     files_set = set()
     for file in files:
         if file in files_set:
-            raise InvalidCheck("Duplicated file `{}` in @{}".format(file, c.cmd))
+            raise InvalidCheck("Duplicated file `{}` in {}".format(file, c.cmd))
         files_set.add(file)
     folder_set = set([f for f in os.listdir(folder) if f != "." and f != ".."])
 
@@ -590,7 +610,7 @@ def check_command(c, cache):
         if c.cmd in ['has', 'hasraw', 'matches', 'matchesraw']:  # string test
             regexp = c.cmd.startswith('matches')
 
-            # @has <path> = file existence
+            # has <path> = file existence
             if len(c.args) == 1 and not regexp and 'raw' not in c.cmd:
                 try:
                     cache.get_file(c.args[0])
@@ -598,40 +618,40 @@ def check_command(c, cache):
                 except FailedCheck as err:
                     cerr = str(err)
                     ret = False
-            # @hasraw/matchesraw <path> <pat> = string test
+            # hasraw/matchesraw <path> <pat> = string test
             elif len(c.args) == 2 and 'raw' in c.cmd:
                 cerr = "`PATTERN` did not match"
                 ret = check_string(cache.get_file(c.args[0]), c.args[1], regexp)
-            # @has/matches <path> <pat> <match> = XML tree test
+            # has/matches <path> <pat> <match> = XML tree test
             elif len(c.args) == 3 and 'raw' not in c.cmd:
                 cerr = "`XPATH PATTERN` did not match"
                 ret = get_nb_matching_elements(cache, c, regexp, True) != 0
             else:
-                raise InvalidCheck('Invalid number of @{} arguments'.format(c.cmd))
+                raise InvalidCheck('Invalid number of {} arguments'.format(c.cmd))
 
         elif c.cmd == 'files': # check files in given folder
-            if len(c.args) != 2: # @files <folder path> <file list>
-                raise InvalidCheck("Invalid number of @{} arguments".format(c.cmd))
+            if len(c.args) != 2: # files <folder path> <file list>
+                raise InvalidCheck("Invalid number of {} arguments".format(c.cmd))
             elif c.negated:
-                raise InvalidCheck("@{} doesn't support negative check".format(c.cmd))
+                raise InvalidCheck("{} doesn't support negative check".format(c.cmd))
             ret = check_files_in_folder(c, cache, c.args[0], c.args[1])
 
         elif c.cmd == 'count':  # count test
-            if len(c.args) == 3:  # @count <path> <pat> <count> = count test
+            if len(c.args) == 3:  # count <path> <pat> <count> = count test
                 expected = int(c.args[2])
                 found = get_tree_count(cache.get_tree(c.args[0]), c.args[1])
                 cerr = "Expected {} occurrences but found {}".format(expected, found)
                 ret = expected == found
-            elif len(c.args) == 4:  # @count <path> <pat> <text> <count> = count test
+            elif len(c.args) == 4:  # count <path> <pat> <text> <count> = count test
                 expected = int(c.args[3])
                 found = get_nb_matching_elements(cache, c, False, False)
                 cerr = "Expected {} occurrences but found {}".format(expected, found)
                 ret = found == expected
             else:
-                raise InvalidCheck('Invalid number of @{} arguments'.format(c.cmd))
+                raise InvalidCheck('Invalid number of {} arguments'.format(c.cmd))
 
         elif c.cmd == 'snapshot':  # snapshot test
-            if len(c.args) == 3:  # @snapshot <snapshot-name> <html-path> <xpath>
+            if len(c.args) == 3:  # snapshot <snapshot-name> <html-path> <xpath>
                 [snapshot_name, html_path, pattern] = c.args
                 tree = cache.get_tree(html_path)
                 xpath = normalize_xpath(pattern)
@@ -654,10 +674,10 @@ def check_command(c, cache):
                 else:
                     raise FailedCheck('Expected 1 match, but found {}'.format(len(subtrees)))
             else:
-                raise InvalidCheck('Invalid number of @{} arguments'.format(c.cmd))
+                raise InvalidCheck('Invalid number of {} arguments'.format(c.cmd))
 
         elif c.cmd == 'has-dir':  # has-dir test
-            if len(c.args) == 1:  # @has-dir <path> = has-dir test
+            if len(c.args) == 1:  # has-dir <path> = has-dir test
                 try:
                     cache.get_dir(c.args[0])
                     ret = True
@@ -665,22 +685,22 @@ def check_command(c, cache):
                     cerr = str(err)
                     ret = False
             else:
-                raise InvalidCheck('Invalid number of @{} arguments'.format(c.cmd))
+                raise InvalidCheck('Invalid number of {} arguments'.format(c.cmd))
 
         elif c.cmd == 'valid-html':
-            raise InvalidCheck('Unimplemented @valid-html')
+            raise InvalidCheck('Unimplemented valid-html')
 
         elif c.cmd == 'valid-links':
-            raise InvalidCheck('Unimplemented @valid-links')
+            raise InvalidCheck('Unimplemented valid-links')
 
         else:
-            raise InvalidCheck('Unrecognized @{}'.format(c.cmd))
+            raise InvalidCheck('Unrecognized {}'.format(c.cmd))
 
         if ret == c.negated:
             raise FailedCheck(cerr)
 
     except FailedCheck as err:
-        message = '@{}{} check failed'.format('!' if c.negated else '', c.cmd)
+        message = '{}{} check failed'.format('!' if c.negated else '', c.cmd)
         print_err(c.lineno, c.context, str(err), message)
     except InvalidCheck as err:
         print_err(c.lineno, c.context, str(err))
diff --git a/src/etc/natvis/intrinsic.natvis b/src/etc/natvis/intrinsic.natvis
index 8c16a562e34..49e0ce319ef 100644
--- a/src/etc/natvis/intrinsic.natvis
+++ b/src/etc/natvis/intrinsic.natvis
@@ -33,6 +33,32 @@
       </ArrayItems>
     </Expand>
   </Type>
+  <Type Name="f16">
+    <Intrinsic Name="sign_mask" Expression="(unsigned __int16) 0x8000" />
+    <Intrinsic Name="exponent_mask" Expression="(unsigned __int16) 0x7c00" />
+    <Intrinsic Name="significand_mask" Expression="(unsigned __int16) 0x03ff" />
+    <Intrinsic Name="sign_bit" Expression="(unsigned __int16) (bits &amp; sign_mask())" />
+    <Intrinsic Name="exponent_bits" Expression="(unsigned __int16) (bits &amp; exponent_mask())" />
+    <Intrinsic Name="significand_bits" Expression="(unsigned __int16) (bits &amp; significand_mask())" />
+
+    <Intrinsic Name="if_set" Expression="(bits &amp; mask) != 0 ? value : 1.0">
+      <Parameter Name="mask" Type="unsigned __int16" />
+      <Parameter Name="value" Type="float" />
+    </Intrinsic>
+    <!-- Calculates 2**exp without needing a pow function. Each float in if_set() is the square of the previous float. 32768 == 2.pow(bias), bias == 15 -->
+    <Intrinsic Name="two_pow_exponent" Expression="if_set(0x0400, 2.0) * if_set(0x0800, 4.0) * if_set(0x1000, 16.0) * if_set(0x2000, 256.0) * if_set(0x4000, 65536.0) / 32768.0" />
+    <!-- Calculates 0.significand, without any implicit bit. 1024 == 2.pow(explicit significand width), explicit significand width == 10 -->
+    <Intrinsic Name="raw_significand" Expression="((float) significand_bits()) / 1024.0" />
+    <Intrinsic Name="sign" Expression="sign_bit() == 0 ? 1.0 : -1.0" />
+
+    <DisplayString Condition="bits == 0x7c00">inf</DisplayString>
+    <DisplayString Condition="bits == 0xfc00">-inf</DisplayString>
+    <DisplayString Condition="exponent_bits() == exponent_mask()">NaN</DisplayString>
+    <!-- Subnormal or zero (16384 == 2.pow(bias - 1), bias - 1 == 14) -->
+    <DisplayString Condition="exponent_bits() == 0">{(float) (sign() * raw_significand() / 16384.0)}</DisplayString>
+    <!-- Normal -->
+    <DisplayString>{(float) (sign() * (raw_significand() + 1.0) * two_pow_exponent())}</DisplayString>
+  </Type>
   <Type Name="tuple$&lt;&gt;">
     <DisplayString>()</DisplayString>
   </Type>
diff --git a/src/etc/pre-push.sh b/src/etc/pre-push.sh
index c9e1a2733fd..6f86c7ab8a4 100755
--- a/src/etc/pre-push.sh
+++ b/src/etc/pre-push.sh
@@ -7,8 +7,6 @@
 
 set -Euo pipefail
 
-# https://github.com/rust-lang/rust/issues/77620#issuecomment-705144570
-unset GIT_DIR
 ROOT_DIR="$(git rev-parse --show-toplevel)"
 
 echo "Running pre-push script $ROOT_DIR/x test tidy"
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index 31222f213d8..51fb126cb34 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -13,6 +13,7 @@ base64 = "0.21.7"
 itertools = "0.12"
 indexmap = "2"
 minifier = "0.3.0"
+pulldown-cmark-old = { version = "0.9.6", package = "pulldown-cmark", default-features = false }
 regex = "1"
 rustdoc-json-types = { path = "../rustdoc-json-types" }
 serde_json = "1.0"
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index da41f974068..aa596897fc4 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -549,7 +549,7 @@ fn clean_generic_param_def<'tcx>(
                 },
             )
         }
-        ty::GenericParamDefKind::Const { has_default, is_host_effect } => (
+        ty::GenericParamDefKind::Const { has_default, synthetic, is_host_effect: _ } => (
             def.name,
             GenericParamDefKind::Const {
                 ty: Box::new(clean_middle_ty(
@@ -572,7 +572,7 @@ fn clean_generic_param_def<'tcx>(
                 } else {
                     None
                 },
-                is_host_effect,
+                synthetic,
             },
         ),
     };
@@ -628,13 +628,13 @@ fn clean_generic_param<'tcx>(
                 },
             )
         }
-        hir::GenericParamKind::Const { ty, default, is_host_effect } => (
+        hir::GenericParamKind::Const { ty, default, synthetic, is_host_effect: _ } => (
             param.name.ident().name,
             GenericParamDefKind::Const {
                 ty: Box::new(clean_ty(ty, cx)),
                 default: default
                     .map(|ct| Box::new(ty::Const::from_anon_const(cx.tcx, ct.def_id).to_string())),
-                is_host_effect,
+                synthetic,
             },
         ),
     };
@@ -1404,14 +1404,17 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
 
             let mut predicates = tcx.explicit_predicates_of(assoc_item.def_id).predicates;
             if let ty::TraitContainer = assoc_item.container {
-                let bounds =
-                    tcx.explicit_item_bounds(assoc_item.def_id).instantiate_identity_iter_copied();
+                let bounds = tcx.explicit_item_bounds(assoc_item.def_id).iter_identity_copied();
                 predicates = tcx.arena.alloc_from_iter(bounds.chain(predicates.iter().copied()));
             }
             let mut generics = clean_ty_generics(
                 cx,
                 tcx.generics_of(assoc_item.def_id),
-                ty::GenericPredicates { parent: None, predicates },
+                ty::GenericPredicates {
+                    parent: None,
+                    predicates,
+                    effects_min_tys: ty::List::empty(),
+                },
             );
             simplify::move_bounds_to_generic_parameters(&mut generics);
 
@@ -3077,9 +3080,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>(
     let def_id = item.owner_id.to_def_id();
     cx.with_param_env(def_id, |cx| {
         let kind = match item.kind {
-            // FIXME(missing_unsafe_on_extern) handle safety of foreign fns.
-            // Safety was added as part of the implementation of unsafe extern blocks PR #124482
-            hir::ForeignItemKind::Fn(decl, names, generics, _) => {
+            hir::ForeignItemKind::Fn(decl, names, generics, safety) => {
                 let (generics, decl) = enter_impl_trait(cx, |cx| {
                     // NOTE: generics must be cleaned before args
                     let generics = clean_generics(generics, cx);
@@ -3087,13 +3088,12 @@ fn clean_maybe_renamed_foreign_item<'tcx>(
                     let decl = clean_fn_decl_with_args(cx, decl, None, args);
                     (generics, decl)
                 });
-                ForeignFunctionItem(Box::new(Function { decl, generics }))
-            }
-            // FIXME(missing_unsafe_on_extern) handle safety of foreign statics.
-            // Safety was added as part of the implementation of unsafe extern blocks PR #124482
-            hir::ForeignItemKind::Static(ty, mutability, _) => {
-                ForeignStaticItem(Static { type_: clean_ty(ty, cx), mutability, expr: None })
+                ForeignFunctionItem(Box::new(Function { decl, generics }), safety)
             }
+            hir::ForeignItemKind::Static(ty, mutability, safety) => ForeignStaticItem(
+                Static { type_: clean_ty(ty, cx), mutability, expr: None },
+                safety,
+            ),
             hir::ForeignItemKind::Type => ForeignTypeItem,
         };
 
diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs
index af61eb6ae8d..58eef36677b 100644
--- a/src/librustdoc/clean/simplify.rs
+++ b/src/librustdoc/clean/simplify.rs
@@ -113,7 +113,7 @@ fn trait_is_same_or_supertrait(cx: &DocContext<'_>, child: DefId, trait_: DefId)
     if child == trait_ {
         return true;
     }
-    let predicates = cx.tcx.super_predicates_of(child);
+    let predicates = cx.tcx.explicit_super_predicates_of(child);
     debug_assert!(cx.tcx.generics_of(child).has_self);
     let self_ty = cx.tcx.types.self_param;
     predicates
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 69678b727c1..fe01d17b08a 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -639,14 +639,14 @@ impl Item {
             hir::FnHeader { safety: sig.safety(), abi: sig.abi(), constness, asyncness }
         }
         let header = match *self.kind {
-            ItemKind::ForeignFunctionItem(_) => {
+            ItemKind::ForeignFunctionItem(_, safety) => {
                 let def_id = self.def_id().unwrap();
                 let abi = tcx.fn_sig(def_id).skip_binder().abi();
                 hir::FnHeader {
                     safety: if abi == Abi::RustIntrinsic {
                         intrinsic_operation_unsafety(tcx, def_id.expect_local())
                     } else {
-                        hir::Safety::Unsafe
+                        safety
                     },
                     abi,
                     constness: if tcx.is_const_fn(def_id)
@@ -842,9 +842,9 @@ pub(crate) enum ItemKind {
     StructFieldItem(Type),
     VariantItem(Variant),
     /// `fn`s from an extern block
-    ForeignFunctionItem(Box<Function>),
+    ForeignFunctionItem(Box<Function>, hir::Safety),
     /// `static`s from an extern block
-    ForeignStaticItem(Static),
+    ForeignStaticItem(Static, hir::Safety),
     /// `type`s from an extern block
     ForeignTypeItem,
     MacroItem(Macro),
@@ -893,8 +893,8 @@ impl ItemKind {
             | TyMethodItem(_)
             | MethodItem(_, _)
             | StructFieldItem(_)
-            | ForeignFunctionItem(_)
-            | ForeignStaticItem(_)
+            | ForeignFunctionItem(_, _)
+            | ForeignStaticItem(_, _)
             | ForeignTypeItem
             | MacroItem(_)
             | ProcMacroItem(_)
@@ -924,8 +924,8 @@ impl ItemKind {
                 | StaticItem(_)
                 | ConstantItem(_, _, _)
                 | TraitAliasItem(_)
-                | ForeignFunctionItem(_)
-                | ForeignStaticItem(_)
+                | ForeignFunctionItem(_, _)
+                | ForeignStaticItem(_, _)
                 | ForeignTypeItem
                 | MacroItem(_)
                 | ProcMacroItem(_)
@@ -1286,7 +1286,7 @@ impl GenericBound {
     }
 }
 
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
 pub(crate) struct Lifetime(pub Symbol);
 
 impl Lifetime {
@@ -1321,7 +1321,7 @@ pub(crate) enum GenericParamDefKind {
     Lifetime { outlives: ThinVec<Lifetime> },
     Type { bounds: ThinVec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
     // Option<Box<String>> makes this type smaller than `Option<String>` would.
-    Const { ty: Box<Type>, default: Option<Box<String>>, is_host_effect: bool },
+    Const { ty: Box<Type>, default: Option<Box<String>>, synthetic: bool },
 }
 
 impl GenericParamDefKind {
@@ -1345,7 +1345,7 @@ impl GenericParamDef {
     pub(crate) fn is_synthetic_param(&self) -> bool {
         match self.kind {
             GenericParamDefKind::Lifetime { .. } => false,
-            GenericParamDefKind::Const { is_host_effect, .. } => is_host_effect,
+            GenericParamDefKind::Const { synthetic: is_host_effect, .. } => is_host_effect,
             GenericParamDefKind::Type { synthetic, .. } => synthetic,
         }
     }
@@ -2557,7 +2557,7 @@ pub(crate) struct ProcMacro {
 /// * the `A: Bound` in `Trait<A: Bound>`
 /// * the `RetTy` in `Trait(ArgTy, ArgTy) -> RetTy`
 /// * the `C = { Ct }` in `Trait<C = { Ct }>` (feature `associated_const_equality`)
-/// * the `f(): Bound` in `Trait<f(): Bound>` (feature `return_type_notation`)
+/// * the `f(..): Bound` in `Trait<f(..): Bound>` (feature `return_type_notation`)
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub(crate) struct AssocItemConstraint {
     pub(crate) assoc: PathSegment,
diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs
index c85b955d4c5..346e9a4e113 100644
--- a/src/librustdoc/fold.rs
+++ b/src/librustdoc/fold.rs
@@ -84,8 +84,8 @@ pub(crate) trait DocFolder: Sized {
             | TyMethodItem(_)
             | MethodItem(_, _)
             | StructFieldItem(_)
-            | ForeignFunctionItem(_)
-            | ForeignStaticItem(_)
+            | ForeignFunctionItem(..)
+            | ForeignStaticItem(..)
             | ForeignTypeItem
             | MacroItem(_)
             | ProcMacroItem(_)
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index bae929c64ea..a7f0df5afa9 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -54,7 +54,8 @@ use crate::html::render::small_url_encode;
 use crate::html::toc::TocBuilder;
 
 use pulldown_cmark::{
-    html, BrokenLink, CodeBlockKind, CowStr, Event, LinkType, OffsetIter, Options, Parser, Tag,
+    html, BrokenLink, BrokenLinkCallback, CodeBlockKind, CowStr, Event, LinkType, OffsetIter,
+    Options, Parser, Tag, TagEnd,
 };
 
 #[cfg(test)]
@@ -230,7 +231,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
         let mut original_text = String::new();
         for event in &mut self.inner {
             match event {
-                Event::End(Tag::CodeBlock(..)) => break,
+                Event::End(TagEnd::CodeBlock) => break,
                 Event::Text(ref s) => {
                     original_text.push_str(s);
                 }
@@ -359,16 +360,17 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for LinkReplacer<'a, I> {
         match &mut event {
             // This is a shortcut link that was resolved by the broken_link_callback: `[fn@f]`
             // Remove any disambiguator.
-            Some(Event::Start(Tag::Link(
+            Some(Event::Start(Tag::Link {
                 // [fn@f] or [fn@f][]
-                LinkType::ShortcutUnknown | LinkType::CollapsedUnknown,
-                dest,
+                link_type: LinkType::ShortcutUnknown | LinkType::CollapsedUnknown,
+                dest_url,
                 title,
-            ))) => {
-                debug!("saw start of shortcut link to {dest} with title {title}");
+                ..
+            })) => {
+                debug!("saw start of shortcut link to {dest_url} with title {title}");
                 // If this is a shortcut link, it was resolved by the broken_link_callback.
                 // So the URL will already be updated properly.
-                let link = self.links.iter().find(|&link| *link.href == **dest);
+                let link = self.links.iter().find(|&link| *link.href == **dest_url);
                 // Since this is an external iterator, we can't replace the inner text just yet.
                 // Store that we saw a link so we know to replace it later.
                 if let Some(link) = link {
@@ -381,16 +383,9 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for LinkReplacer<'a, I> {
                 }
             }
             // Now that we're done with the shortcut link, don't replace any more text.
-            Some(Event::End(Tag::Link(
-                LinkType::ShortcutUnknown | LinkType::CollapsedUnknown,
-                dest,
-                _,
-            ))) => {
-                debug!("saw end of shortcut link to {dest}");
-                if self.links.iter().any(|link| *link.href == **dest) {
-                    assert!(self.shortcut_link.is_some(), "saw closing link without opening tag");
-                    self.shortcut_link = None;
-                }
+            Some(Event::End(TagEnd::Link)) if self.shortcut_link.is_some() => {
+                debug!("saw end of shortcut link");
+                self.shortcut_link = None;
             }
             // Handle backticks in inline code blocks, but only if we're in the middle of a shortcut link.
             // [`fn@f`]
@@ -433,9 +428,11 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for LinkReplacer<'a, I> {
             }
             // If this is a link, but not a shortcut link,
             // replace the URL, since the broken_link_callback was not called.
-            Some(Event::Start(Tag::Link(_, dest, title))) => {
-                if let Some(link) = self.links.iter().find(|&link| *link.original_text == **dest) {
-                    *dest = CowStr::Borrowed(link.href.as_ref());
+            Some(Event::Start(Tag::Link { dest_url, title, .. })) => {
+                if let Some(link) =
+                    self.links.iter().find(|&link| *link.original_text == **dest_url)
+                {
+                    *dest_url = CowStr::Borrowed(link.href.as_ref());
                     if title.is_empty() && !link.tooltip.is_empty() {
                         *title = CowStr::Borrowed(link.tooltip.as_ref());
                     }
@@ -477,9 +474,9 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for TableWrapper<'a, I> {
                 self.stored_events.push_back(Event::Start(Tag::Table(t)));
                 Event::Html(CowStr::Borrowed("<div>"))
             }
-            Event::End(Tag::Table(t)) => {
+            Event::End(TagEnd::Table) => {
                 self.stored_events.push_back(Event::Html(CowStr::Borrowed("</div>")));
-                Event::End(Tag::Table(t))
+                Event::End(TagEnd::Table)
             }
             e => e,
         })
@@ -519,11 +516,11 @@ impl<'a, 'b, 'ids, I: Iterator<Item = SpannedEvent<'a>>> Iterator
         }
 
         let event = self.inner.next();
-        if let Some((Event::Start(Tag::Heading(level, _, _)), _)) = event {
+        if let Some((Event::Start(Tag::Heading { level, .. }), _)) = event {
             let mut id = String::new();
             for event in &mut self.inner {
                 match &event.0 {
-                    Event::End(Tag::Heading(..)) => break,
+                    Event::End(TagEnd::Heading(_)) => break,
                     Event::Text(text) | Event::Code(text) => {
                         id.extend(text.chars().filter_map(slugify));
                         self.buf.push_back(event);
@@ -566,27 +563,27 @@ impl<'a, I: Iterator<Item = Event<'a>>> SummaryLine<'a, I> {
     }
 }
 
-fn check_if_allowed_tag(t: &Tag<'_>) -> bool {
+fn check_if_allowed_tag(t: &TagEnd) -> bool {
     matches!(
         t,
-        Tag::Paragraph
-            | Tag::Emphasis
-            | Tag::Strong
-            | Tag::Strikethrough
-            | Tag::Link(..)
-            | Tag::BlockQuote
+        TagEnd::Paragraph
+            | TagEnd::Emphasis
+            | TagEnd::Strong
+            | TagEnd::Strikethrough
+            | TagEnd::Link
+            | TagEnd::BlockQuote
     )
 }
 
-fn is_forbidden_tag(t: &Tag<'_>) -> bool {
+fn is_forbidden_tag(t: &TagEnd) -> bool {
     matches!(
         t,
-        Tag::CodeBlock(_)
-            | Tag::Table(_)
-            | Tag::TableHead
-            | Tag::TableRow
-            | Tag::TableCell
-            | Tag::FootnoteDefinition(_)
+        TagEnd::CodeBlock
+            | TagEnd::Table
+            | TagEnd::TableHead
+            | TagEnd::TableRow
+            | TagEnd::TableCell
+            | TagEnd::FootnoteDefinition
     )
 }
 
@@ -604,12 +601,12 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for SummaryLine<'a, I> {
             let mut is_start = true;
             let is_allowed_tag = match event {
                 Event::Start(ref c) => {
-                    if is_forbidden_tag(c) {
+                    if is_forbidden_tag(&c.to_end()) {
                         self.skipped_tags += 1;
                         return None;
                     }
                     self.depth += 1;
-                    check_if_allowed_tag(c)
+                    check_if_allowed_tag(&c.to_end())
                 }
                 Event::End(ref c) => {
                     if is_forbidden_tag(c) {
@@ -633,7 +630,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for SummaryLine<'a, I> {
                 if is_start {
                     Some(Event::Start(Tag::Paragraph))
                 } else {
-                    Some(Event::End(Tag::Paragraph))
+                    Some(Event::End(TagEnd::Paragraph))
                 }
             } else {
                 Some(event)
@@ -679,7 +676,7 @@ impl<'a, I: Iterator<Item = SpannedEvent<'a>>> Iterator for Footnotes<'a, I> {
                 Some((Event::Start(Tag::FootnoteDefinition(def)), _)) => {
                     let mut content = Vec::new();
                     for (event, _) in &mut self.inner {
-                        if let Event::End(Tag::FootnoteDefinition(..)) = event {
+                        if let Event::End(TagEnd::FootnoteDefinition) = event {
                             break;
                         }
                         content.push(event);
@@ -696,7 +693,7 @@ impl<'a, I: Iterator<Item = SpannedEvent<'a>>> Iterator for Footnotes<'a, I> {
                         for (mut content, id) in v {
                             write!(ret, "<li id=\"fn{id}\">").unwrap();
                             let mut is_paragraph = false;
-                            if let Some(&Event::End(Tag::Paragraph)) = content.last() {
+                            if let Some(&Event::End(TagEnd::Paragraph)) = content.last() {
                                 content.pop();
                                 is_paragraph = true;
                             }
@@ -806,7 +803,7 @@ pub(crate) fn find_codes<T: doctest::DoctestVisitor>(
                 tests.visit_test(text, block_info, line);
                 prev_offset = offset.start;
             }
-            Event::Start(Tag::Heading(level, _, _)) => {
+            Event::Start(Tag::Heading { level, .. }) => {
                 register_header = Some(level as u32);
             }
             Event::Text(ref s) if register_header.is_some() => {
@@ -1432,7 +1429,7 @@ impl MarkdownItemInfo<'_> {
 
         // Treat inline HTML as plain text.
         let p = p.map(|event| match event.0 {
-            Event::Html(text) => (Event::Text(text), event.1),
+            Event::Html(text) | Event::InlineHtml(text) => (Event::Text(text), event.1),
             _ => event,
         });
 
@@ -1442,7 +1439,7 @@ impl MarkdownItemInfo<'_> {
         let p = Footnotes::new(p);
         let p = TableWrapper::new(p.map(|(ev, _)| ev));
         let p = p.filter(|event| {
-            !matches!(event, Event::Start(Tag::Paragraph) | Event::End(Tag::Paragraph))
+            !matches!(event, Event::Start(Tag::Paragraph) | Event::End(TagEnd::Paragraph))
         });
         html::push_html(&mut s, p);
 
@@ -1472,7 +1469,7 @@ impl MarkdownSummaryLine<'_> {
         let mut s = String::new();
 
         let without_paragraphs = LinkReplacer::new(&mut summary, links).filter(|event| {
-            !matches!(event, Event::Start(Tag::Paragraph) | Event::End(Tag::Paragraph))
+            !matches!(event, Event::Start(Tag::Paragraph) | Event::End(TagEnd::Paragraph))
         });
 
         html::push_html(&mut s, without_paragraphs);
@@ -1544,8 +1541,8 @@ fn markdown_summary_with_limit(
                 _ => {}
             },
             Event::End(tag) => match tag {
-                Tag::Emphasis | Tag::Strong => buf.close_tag(),
-                Tag::Paragraph | Tag::Heading(..) => return ControlFlow::Break(()),
+                TagEnd::Emphasis | TagEnd::Strong => buf.close_tag(),
+                TagEnd::Paragraph | TagEnd::Heading(_) => return ControlFlow::Break(()),
                 _ => {}
             },
             Event::HardBreak | Event::SoftBreak => buf.push(" ")?,
@@ -1605,8 +1602,8 @@ pub(crate) fn plain_text_summary(md: &str, link_names: &[RenderedLink]) -> Strin
             }
             Event::HardBreak | Event::SoftBreak => s.push(' '),
             Event::Start(Tag::CodeBlock(..)) => break,
-            Event::End(Tag::Paragraph) => break,
-            Event::End(Tag::Heading(..)) => break,
+            Event::End(TagEnd::Paragraph) => break,
+            Event::End(TagEnd::Heading(..)) => break,
             _ => (),
         }
     }
@@ -1765,7 +1762,7 @@ pub(crate) fn markdown_links<'md, R>(
 
     while let Some((event, span)) = event_iter.next() {
         match event {
-            Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => {
+            Event::Start(Tag::Link { link_type, dest_url, .. }) if may_be_doc_link(link_type) => {
                 let range = match link_type {
                     // Link is pulled from the link itself.
                     LinkType::ReferenceUnknown | LinkType::ShortcutUnknown => {
@@ -1775,7 +1772,7 @@ pub(crate) fn markdown_links<'md, R>(
                     LinkType::Inline => span_for_offset_backward(span, b'(', b')'),
                     // Link is pulled from elsewhere in the document.
                     LinkType::Reference | LinkType::Collapsed | LinkType::Shortcut => {
-                        span_for_link(&dest, span)
+                        span_for_link(&dest_url, span)
                     }
                     LinkType::Autolink | LinkType::Email => unreachable!(),
                 };
@@ -1795,7 +1792,7 @@ pub(crate) fn markdown_links<'md, R>(
 
                 if let Some(link) = preprocess_link(MarkdownLink {
                     kind: link_type,
-                    link: dest.into_string(),
+                    link: dest_url.into_string(),
                     display_text,
                     range,
                 }) {
@@ -1810,8 +1807,8 @@ pub(crate) fn markdown_links<'md, R>(
 }
 
 /// Collects additional data of link.
-fn collect_link_data<'input, 'callback>(
-    event_iter: &mut OffsetIter<'input, 'callback>,
+fn collect_link_data<'input, F: BrokenLinkCallback<'input>>(
+    event_iter: &mut OffsetIter<'input, F>,
 ) -> Option<String> {
     let mut display_text: Option<String> = None;
     let mut append_text = |text: CowStr<'_>| {
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index e1f79254b24..00973865915 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -254,7 +254,7 @@ pub(super) fn print_item(cx: &mut Context<'_>, item: &clean::Item, buf: &mut Buf
 
     match &*item.kind {
         clean::ModuleItem(ref m) => item_module(buf, cx, item, &m.items),
-        clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f) => {
+        clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f, _) => {
             item_function(buf, cx, item, f)
         }
         clean::TraitItem(ref t) => item_trait(buf, cx, item, t),
@@ -265,7 +265,8 @@ pub(super) fn print_item(cx: &mut Context<'_>, item: &clean::Item, buf: &mut Buf
         clean::MacroItem(ref m) => item_macro(buf, cx, item, m),
         clean::ProcMacroItem(ref m) => item_proc_macro(buf, cx, item, m),
         clean::PrimitiveItem(_) => item_primitive(buf, cx, item),
-        clean::StaticItem(ref i) | clean::ForeignStaticItem(ref i) => item_static(buf, cx, item, i),
+        clean::StaticItem(ref i) => item_static(buf, cx, item, i, None),
+        clean::ForeignStaticItem(ref i, safety) => item_static(buf, cx, item, i, Some(*safety)),
         clean::ConstantItem(generics, ty, c) => item_constant(buf, cx, item, generics, ty, c),
         clean::ForeignTypeItem => item_foreign_type(buf, cx, item),
         clean::KeywordItem => item_keyword(buf, cx, item),
@@ -491,11 +492,14 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
                 }
 
                 let unsafety_flag = match *myitem.kind {
-                    clean::FunctionItem(_) | clean::ForeignFunctionItem(_)
+                    clean::FunctionItem(_) | clean::ForeignFunctionItem(..)
                         if myitem.fn_header(tcx).unwrap().safety == hir::Safety::Unsafe =>
                     {
                         "<sup title=\"unsafe function\">⚠</sup>"
                     }
+                    clean::ForeignStaticItem(_, hir::Safety::Unsafe) => {
+                        "<sup title=\"unsafe static\">⚠</sup>"
+                    }
                     _ => "",
                 };
 
@@ -1957,13 +1961,22 @@ fn item_fields(
     }
 }
 
-fn item_static(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) {
+fn item_static(
+    w: &mut impl fmt::Write,
+    cx: &mut Context<'_>,
+    it: &clean::Item,
+    s: &clean::Static,
+    safety: Option<hir::Safety>,
+) {
     wrap_item(w, |buffer| {
         render_attributes_in_code(buffer, it, cx);
         write!(
             buffer,
-            "{vis}static {mutability}{name}: {typ}",
+            "{vis}{safe}static {mutability}{name}: {typ}",
             vis = visibility_print_with_space(it, cx),
+            safe = safety
+                .map(|safe| if safe == hir::Safety::Unsafe { "unsafe " } else { "" })
+                .unwrap_or(""),
             mutability = s.mutability.print_with_space(),
             name = it.name.unwrap(),
             typ = s.type_.print(cx)
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index c806bf1cc66..8fd56eae37f 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -507,8 +507,7 @@ else if (window.initSearch) window.initSearch(searchIndex);
                 // Be aware of `tests/rustdoc/type-alias/deeply-nested-112515.rs` which might regress.
                 let Some(impl_did) = impl_item_id.as_def_id() else { continue };
                 let for_ty = self.cx.tcx().type_of(impl_did).skip_binder();
-                let reject_cx =
-                    DeepRejectCtxt { treat_obligation_params: TreatParams::AsCandidateKey };
+                let reject_cx = DeepRejectCtxt::new(self.cx.tcx(), TreatParams::AsCandidateKey);
                 if !reject_cx.types_may_unify(aliased_ty, for_ty) {
                     continue;
                 }
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index a0ab262bf0b..86af38f3ee7 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -3293,10 +3293,9 @@ ${item.displayPath}<span class="${type}">${name}</span>\
         }
         // call after consuming `{`
         decodeList() {
-            const cb = "}".charCodeAt(0);
             let c = this.string.charCodeAt(this.offset);
             const ret = [];
-            while (c !== cb) {
+            while (c !== 125) { // 125 = "}"
                 ret.push(this.decode());
                 c = this.string.charCodeAt(this.offset);
             }
@@ -3305,14 +3304,13 @@ ${item.displayPath}<span class="${type}">${name}</span>\
         }
         // consumes and returns a list or integer
         decode() {
-            const [ob, la] = ["{", "`"].map(c => c.charCodeAt(0));
             let n = 0;
             let c = this.string.charCodeAt(this.offset);
-            if (c === ob) {
+            if (c === 123) { // 123 = "{"
                 this.offset += 1;
                 return this.decodeList();
             }
-            while (c < la) {
+            while (c < 96) { // 96 = "`"
                 n = (n << 4) | (c & 0xF);
                 this.offset += 1;
                 c = this.string.charCodeAt(this.offset);
@@ -3325,15 +3323,14 @@ ${item.displayPath}<span class="${type}">${name}</span>\
         }
         next() {
             const c = this.string.charCodeAt(this.offset);
-            const [zero, ua, la] = ["0", "@", "`"].map(c => c.charCodeAt(0));
             // sixteen characters after "0" are backref
-            if (c >= zero && c < ua) {
+            if (c >= 48 && c < 64) { // 48 = "0", 64 = "@"
                 this.offset += 1;
-                return this.backrefQueue[c - zero];
+                return this.backrefQueue[c - 48];
             }
             // special exception: 0 doesn't use backref encoding
             // it's already one character, and it's always nullish
-            if (c === la) {
+            if (c === 96) { // 96 = "`"
                 this.offset += 1;
                 return this.cons(0);
             }
@@ -3472,7 +3469,6 @@ ${item.displayPath}<span class="${type}">${name}</span>\
         searchIndex = [];
         searchIndexDeprecated = new Map();
         searchIndexEmptyDesc = new Map();
-        const charA = "A".charCodeAt(0);
         let currentIndex = 0;
         let id = 0;
 
@@ -3639,7 +3635,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
                 // object defined above.
                 const row = {
                     crate,
-                    ty: itemTypes.charCodeAt(i) - charA,
+                    ty: itemTypes.charCodeAt(i) - 65, // 65 = "A"
                     name: itemNames[i],
                     path,
                     descShard,
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index afafb4fbe4b..5111e363c52 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -10,6 +10,7 @@ use rustc_ast::ast;
 use rustc_attr::DeprecatedSince;
 use rustc_hir::{def::CtorKind, def::DefKind, def_id::DefId};
 use rustc_metadata::rendered_const;
+use rustc_middle::bug;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::symbol::sym;
 use rustc_span::{Pos, Symbol};
@@ -310,14 +311,16 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
         EnumItem(e) => ItemEnum::Enum(e.into_tcx(tcx)),
         VariantItem(v) => ItemEnum::Variant(v.into_tcx(tcx)),
         FunctionItem(f) => ItemEnum::Function(from_function(f, true, header.unwrap(), tcx)),
-        ForeignFunctionItem(f) => ItemEnum::Function(from_function(f, false, header.unwrap(), tcx)),
+        ForeignFunctionItem(f, _) => {
+            ItemEnum::Function(from_function(f, false, header.unwrap(), tcx))
+        }
         TraitItem(t) => ItemEnum::Trait((*t).into_tcx(tcx)),
         TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_tcx(tcx)),
         MethodItem(m, _) => ItemEnum::Function(from_function(m, true, header.unwrap(), tcx)),
         TyMethodItem(m) => ItemEnum::Function(from_function(m, false, header.unwrap(), tcx)),
         ImplItem(i) => ItemEnum::Impl((*i).into_tcx(tcx)),
         StaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)),
-        ForeignStaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)),
+        ForeignStaticItem(s, _) => ItemEnum::Static(s.into_tcx(tcx)),
         ForeignTypeItem => ItemEnum::ForeignType,
         TypeAliasItem(t) => ItemEnum::TypeAlias(t.into_tcx(tcx)),
         OpaqueTyItem(t) => ItemEnum::OpaqueTy(t.into_tcx(tcx)),
@@ -464,7 +467,7 @@ impl FromWithTcx<clean::GenericParamDefKind> for GenericParamDefKind {
                 default: default.map(|x| (*x).into_tcx(tcx)),
                 synthetic,
             },
-            Const { ty, default, is_host_effect: _ } => GenericParamDefKind::Const {
+            Const { ty, default, synthetic: _ } => GenericParamDefKind::Const {
                 type_: (*ty).into_tcx(tcx),
                 default: default.map(|x| *x),
             },
@@ -499,22 +502,26 @@ impl FromWithTcx<clean::WherePredicate> for WherePredicate {
                                     synthetic,
                                 }
                             }
-                            clean::GenericParamDefKind::Const {
-                                ty,
-                                default,
-                                is_host_effect: _,
-                            } => GenericParamDefKind::Const {
-                                type_: (*ty).into_tcx(tcx),
-                                default: default.map(|d| *d),
-                            },
+                            clean::GenericParamDefKind::Const { ty, default, synthetic: _ } => {
+                                GenericParamDefKind::Const {
+                                    type_: (*ty).into_tcx(tcx),
+                                    default: default.map(|d| *d),
+                                }
+                            }
                         };
                         GenericParamDef { name, kind }
                     })
                     .collect(),
             },
-            RegionPredicate { lifetime, bounds } => WherePredicate::RegionPredicate {
+            RegionPredicate { lifetime, bounds } => WherePredicate::LifetimePredicate {
                 lifetime: convert_lifetime(lifetime),
-                bounds: bounds.into_tcx(tcx),
+                outlives: bounds
+                    .iter()
+                    .map(|bound| match bound {
+                        clean::GenericBound::Outlives(lt) => convert_lifetime(*lt),
+                        _ => bug!("found non-outlives-bound on lifetime predicate"),
+                    })
+                    .collect(),
             },
             EqPredicate { lhs, rhs } => {
                 WherePredicate::EqPredicate { lhs: lhs.into_tcx(tcx), rhs: rhs.into_tcx(tcx) }
diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs
index dd2bb47e592..5a8fd3ebb9c 100644
--- a/src/librustdoc/lint.rs
+++ b/src/librustdoc/lint.rs
@@ -66,7 +66,7 @@ where
 macro_rules! declare_rustdoc_lint {
     (
         $(#[$attr:meta])* $name: ident, $level: ident, $descr: literal $(,)?
-        $(@feature_gate = $gate:expr;)?
+        $(@feature_gate = $gate:ident;)?
     ) => {
         declare_tool_lint! {
             $(#[$attr])* pub rustdoc::$name, $level, $descr
@@ -128,7 +128,7 @@ declare_rustdoc_lint! {
     MISSING_DOC_CODE_EXAMPLES,
     Allow,
     "detects publicly-exported items without code samples in their documentation",
-    @feature_gate = rustc_span::symbol::sym::rustdoc_missing_doc_code_examples;
+    @feature_gate = rustdoc_missing_doc_code_examples;
 }
 
 declare_rustdoc_lint! {
@@ -196,6 +196,14 @@ 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,
@@ -209,6 +217,7 @@ pub(crate) static RUSTDOC_LINTS: Lazy<Vec<&'static Lint>> = Lazy::new(|| {
         MISSING_CRATE_LEVEL_DOCS,
         UNESCAPED_BACKTICKS,
         REDUNDANT_EXPLICIT_LINKS,
+        UNPORTABLE_MARKDOWN,
     ]
 });
 
diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs
index 592dd0a145c..9e576002dc3 100644
--- a/src/librustdoc/passes/calculate_doc_coverage.rs
+++ b/src/librustdoc/passes/calculate_doc_coverage.rs
@@ -1,4 +1,5 @@
 //! Calculates information used for the --show-coverage flag.
+
 use crate::clean;
 use crate::core::DocContext;
 use crate::html::markdown::{find_testable_code, ErrorCodes};
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 440b02a1fa7..37f7e7ed385 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -1507,6 +1507,15 @@ impl Disambiguator {
     fn from_str(link: &str) -> Result<Option<(Self, &str, &str)>, (String, Range<usize>)> {
         use Disambiguator::{Kind, Namespace as NS, Primitive};
 
+        let suffixes = [
+            // If you update this list, please also update the relevant rustdoc book section!
+            ("!()", DefKind::Macro(MacroKind::Bang)),
+            ("!{}", DefKind::Macro(MacroKind::Bang)),
+            ("![]", DefKind::Macro(MacroKind::Bang)),
+            ("()", DefKind::Fn),
+            ("!", DefKind::Macro(MacroKind::Bang)),
+        ];
+
         if let Some(idx) = link.find('@') {
             let (prefix, rest) = link.split_at(idx);
             let d = match prefix {
@@ -1530,16 +1539,23 @@ impl Disambiguator {
                 "prim" | "primitive" => Primitive,
                 _ => return Err((format!("unknown disambiguator `{prefix}`"), 0..idx)),
             };
+
+            for (suffix, kind) in suffixes {
+                if let Some(path_str) = rest.strip_suffix(suffix) {
+                    if d.ns() != Kind(kind).ns() {
+                        return Err((
+                            format!("unmatched disambiguator `{prefix}` and suffix `{suffix}`"),
+                            0..idx,
+                        ));
+                    } else if path_str.len() > 1 {
+                        // path_str != "@"
+                        return Ok(Some((d, &path_str[1..], &rest[1..])));
+                    }
+                }
+            }
+
             Ok(Some((d, &rest[1..], &rest[1..])))
         } else {
-            let suffixes = [
-                // If you update this list, please also update the relevant rustdoc book section!
-                ("!()", DefKind::Macro(MacroKind::Bang)),
-                ("!{}", DefKind::Macro(MacroKind::Bang)),
-                ("![]", DefKind::Macro(MacroKind::Bang)),
-                ("()", DefKind::Fn),
-                ("!", DefKind::Macro(MacroKind::Bang)),
-            ];
             for (suffix, kind) in suffixes {
                 if let Some(path_str) = link.strip_suffix(suffix) {
                     // Avoid turning `!` or `()` into an empty string
diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index c92cf9d3e80..9ac9941e521 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -1,6 +1,7 @@
 //! Collects trait impls for each item in the crate. For example, if a crate
 //! defines a struct that implements a trait, this pass will note that the
 //! struct implements that trait.
+
 use super::Pass;
 use crate::clean::*;
 use crate::core::DocContext;
diff --git a/src/librustdoc/passes/lint.rs b/src/librustdoc/passes/lint.rs
index c6d5b7bd346..bc804a340bf 100644
--- a/src/librustdoc/passes/lint.rs
+++ b/src/librustdoc/passes/lint.rs
@@ -6,6 +6,7 @@ mod check_code_block_syntax;
 mod html_tags;
 mod redundant_explicit_links;
 mod unescaped_backticks;
+mod unportable_markdown;
 
 use super::Pass;
 use crate::clean::*;
@@ -31,6 +32,7 @@ impl<'a, 'tcx> DocVisitor for Linter<'a, 'tcx> {
         html_tags::visit_item(self.cx, item);
         unescaped_backticks::visit_item(self.cx, item);
         redundant_explicit_links::visit_item(self.cx, item);
+        unportable_markdown::visit_item(self.cx, item);
 
         self.visit_item_recur(item)
     }
diff --git a/src/librustdoc/passes/lint/bare_urls.rs b/src/librustdoc/passes/lint/bare_urls.rs
index 8f68f6ff476..a4ba718789c 100644
--- a/src/librustdoc/passes/lint/bare_urls.rs
+++ b/src/librustdoc/passes/lint/bare_urls.rs
@@ -19,22 +19,22 @@ pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item) {
     };
     let dox = item.doc_value();
     if !dox.is_empty() {
-        let report_diag =
-            |cx: &DocContext<'_>, msg: &'static str, url: &str, range: Range<usize>| {
-                let sp =
-                    source_span_for_markdown_range(cx.tcx, &dox, &range, &item.attrs.doc_strings)
-                        .unwrap_or_else(|| item.attr_span(cx.tcx));
-                cx.tcx.node_span_lint(crate::lint::BARE_URLS, hir_id, sp, |lint| {
-                    lint.primary_message(msg)
-                        .note("bare URLs are not automatically turned into clickable links")
-                        .span_suggestion(
-                            sp,
-                            "use an automatic link instead",
-                            format!("<{url}>"),
-                            Applicability::MachineApplicable,
-                        );
-                });
-            };
+        let report_diag = |cx: &DocContext<'_>, msg: &'static str, range: Range<usize>| {
+            let sp = source_span_for_markdown_range(cx.tcx, &dox, &range, &item.attrs.doc_strings)
+                .unwrap_or_else(|| item.attr_span(cx.tcx));
+            cx.tcx.node_span_lint(crate::lint::BARE_URLS, hir_id, sp, |lint| {
+                lint.primary_message(msg)
+                    .note("bare URLs are not automatically turned into clickable links")
+                    .multipart_suggestion(
+                        "use an automatic link instead",
+                        vec![
+                            (sp.shrink_to_lo(), "<".to_string()),
+                            (sp.shrink_to_hi(), ">".to_string()),
+                        ],
+                        Applicability::MachineApplicable,
+                    );
+            });
+        };
 
         let mut p = Parser::new_ext(&dox, main_body_opts()).into_offset_iter();
 
@@ -42,11 +42,11 @@ pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item) {
             match event {
                 Event::Text(s) => find_raw_urls(cx, &s, range, &report_diag),
                 // We don't want to check the text inside code blocks or links.
-                Event::Start(tag @ (Tag::CodeBlock(_) | Tag::Link(..))) => {
+                Event::Start(tag @ (Tag::CodeBlock(_) | Tag::Link { .. })) => {
                     while let Some((event, _)) = p.next() {
                         match event {
                             Event::End(end)
-                                if mem::discriminant(&end) == mem::discriminant(&tag) =>
+                                if mem::discriminant(&end) == mem::discriminant(&tag.to_end()) =>
                             {
                                 break;
                             }
@@ -74,17 +74,15 @@ fn find_raw_urls(
     cx: &DocContext<'_>,
     text: &str,
     range: Range<usize>,
-    f: &impl Fn(&DocContext<'_>, &'static str, &str, Range<usize>),
+    f: &impl Fn(&DocContext<'_>, &'static str, Range<usize>),
 ) {
     trace!("looking for raw urls in {text}");
     // For now, we only check "full" URLs (meaning, starting with "http://" or "https://").
     for match_ in URL_REGEX.find_iter(text) {
-        let url = match_.as_str();
         let url_range = match_.range();
         f(
             cx,
             "this URL is not a hyperlink",
-            url,
             Range { start: range.start + url_range.start, end: range.start + url_range.end },
         );
     }
diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs
index c185442fd55..afeb7111e15 100644
--- a/src/librustdoc/passes/lint/check_code_block_syntax.rs
+++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs
@@ -1,4 +1,5 @@
 //! Validates syntax inside Rust code blocks (\`\`\`rust).
+
 use rustc_data_structures::sync::{Lock, Lrc};
 use rustc_errors::{
     emitter::Emitter,
diff --git a/src/librustdoc/passes/lint/html_tags.rs b/src/librustdoc/passes/lint/html_tags.rs
index 25b0c61b826..87dfa5d5389 100644
--- a/src/librustdoc/passes/lint/html_tags.rs
+++ b/src/librustdoc/passes/lint/html_tags.rs
@@ -1,9 +1,10 @@
 //! Detects invalid HTML (like an unclosed `<span>`) in doc comments.
+
 use crate::clean::*;
 use crate::core::DocContext;
 use crate::html::markdown::main_body_opts;
 
-use pulldown_cmark::{BrokenLink, Event, LinkType, Parser, Tag};
+use pulldown_cmark::{BrokenLink, Event, LinkType, Parser, Tag, TagEnd};
 use rustc_resolve::rustdoc::source_span_for_markdown_range;
 
 use std::iter::Peekable;
@@ -139,10 +140,10 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) {
         for (event, range) in p {
             match event {
                 Event::Start(Tag::CodeBlock(_)) => in_code_block = true,
-                Event::Html(text) if !in_code_block => {
+                Event::Html(text) | Event::InlineHtml(text) if !in_code_block => {
                     extract_tags(&mut tags, &text, range, &mut is_in_comment, &report_diag)
                 }
-                Event::End(Tag::CodeBlock(_)) => in_code_block = false,
+                Event::End(TagEnd::CodeBlock) => in_code_block = false,
                 _ => {}
             }
         }
diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs
index 7ab974046b9..b36b41c9f2d 100644
--- a/src/librustdoc/passes/lint/redundant_explicit_links.rs
+++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs
@@ -1,6 +1,8 @@
 use std::ops::Range;
 
-use pulldown_cmark::{BrokenLink, CowStr, Event, LinkType, OffsetIter, Parser, Tag};
+use pulldown_cmark::{
+    BrokenLink, BrokenLinkCallback, CowStr, Event, LinkType, OffsetIter, Parser, Tag,
+};
 use rustc_ast::NodeId;
 use rustc_errors::SuggestionStyle;
 use rustc_hir::def::{DefKind, DocLinkResMap, Namespace, Res};
@@ -95,7 +97,7 @@ fn check_redundant_explicit_link<'md>(
 
     while let Some((event, link_range)) = offset_iter.next() {
         match event {
-            Event::Start(Tag::Link(link_type, dest, _)) => {
+            Event::Start(Tag::Link { link_type, dest_url, .. }) => {
                 let link_data = collect_link_data(&mut offset_iter);
 
                 if let Some(resolvable_link) = link_data.resolvable_link.as_ref() {
@@ -108,7 +110,7 @@ fn check_redundant_explicit_link<'md>(
                     }
                 }
 
-                let explicit_link = dest.to_string();
+                let explicit_link = dest_url.to_string();
                 let display_link = link_data.resolvable_link.clone()?;
 
                 if explicit_link.ends_with(&display_link) || display_link.ends_with(&explicit_link)
@@ -122,7 +124,7 @@ fn check_redundant_explicit_link<'md>(
                                 doc,
                                 resolutions,
                                 link_range,
-                                dest.to_string(),
+                                dest_url.to_string(),
                                 link_data,
                                 if link_type == LinkType::Inline {
                                     (b'(', b')')
@@ -139,7 +141,7 @@ fn check_redundant_explicit_link<'md>(
                                 doc,
                                 resolutions,
                                 link_range,
-                                &dest,
+                                &dest_url,
                                 link_data,
                             );
                         }
@@ -259,7 +261,9 @@ fn find_resolution(resolutions: &DocLinkResMap, path: &str) -> Option<Res<NodeId
 }
 
 /// Collects all necessary data of link.
-fn collect_link_data(offset_iter: &mut OffsetIter<'_, '_>) -> LinkData {
+fn collect_link_data<'input, F: BrokenLinkCallback<'input>>(
+    offset_iter: &mut OffsetIter<'input, F>,
+) -> LinkData {
     let mut resolvable_link = None;
     let mut resolvable_link_range = None;
     let mut display_link = String::new();
diff --git a/src/librustdoc/passes/lint/unportable_markdown.rs b/src/librustdoc/passes/lint/unportable_markdown.rs
new file mode 100644
index 00000000000..5f185377634
--- /dev/null
+++ b/src/librustdoc/passes/lint/unportable_markdown.rs
@@ -0,0 +1,152 @@
+//! 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 crate::clean::Item;
+use crate::core::DocContext;
+use pulldown_cmark as cmarkn;
+use pulldown_cmark_old as cmarko;
+use rustc_lint_defs::Applicability;
+use rustc_resolve::rustdoc::source_span_for_markdown_range;
+use std::collections::{BTreeMap, BTreeSet};
+
+pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) {
+    let tcx = cx.tcx;
+    let Some(hir_id) = DocContext::as_local_hir_id(tcx, item.item_id) else {
+        // If non-local, no need to check anything.
+        return;
+    };
+
+    let dox = item.doc_value();
+    if dox.is_empty() {
+        return;
+    }
+
+    // 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 mut parser_new = cmarkn::Parser::new_ext(&dox, main_body_opts_new()).into_offset_iter();
+        while let Some((event, span)) = parser_new.next() {
+            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 mut parser_old = cmarko::Parser::new_ext(&dox, main_body_opts_old()).into_offset_iter();
+        while let Some((event, span)) = parser_old.next() {
+            if let cmarko::Event::Start(cmarko::Tag::BlockQuote) = event {
+                if !dox[span.clone()].starts_with("> ") {
+                    spaceless_block_quotes.remove(&span.start);
+                }
+            }
+            if let cmarko::Event::FootnoteReference(_) = event {
+                if !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(format!("confusing block quote with no space after the `>` marker"));
+            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_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs
index 95273a225a9..8de7f2379b4 100644
--- a/src/librustdoc/passes/propagate_doc_cfg.rs
+++ b/src/librustdoc/passes/propagate_doc_cfg.rs
@@ -1,4 +1,5 @@
 //! Propagates [`#[doc(cfg(...))]`](https://github.com/rust-lang/rust/issues/43781) to child items.
+
 use std::sync::Arc;
 
 use crate::clean::cfg::Cfg;
diff --git a/src/librustdoc/passes/strip_priv_imports.rs b/src/librustdoc/passes/strip_priv_imports.rs
index 468712ba3d0..7b05756ae21 100644
--- a/src/librustdoc/passes/strip_priv_imports.rs
+++ b/src/librustdoc/passes/strip_priv_imports.rs
@@ -1,5 +1,6 @@
 //! Strips all private import statements (use, extern crate) from a
 //! crate.
+
 use crate::clean;
 use crate::core::DocContext;
 use crate::fold::DocFolder;
diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs
index 3b6f484fde6..1bafa450be9 100644
--- a/src/librustdoc/passes/strip_private.rs
+++ b/src/librustdoc/passes/strip_private.rs
@@ -1,5 +1,6 @@
 //! Strip all private items from the output. Additionally implies strip_priv_imports.
 //! Basically, the goal is to remove items that are not relevant for public documentation.
+
 use crate::clean::{self, ItemIdSet};
 use crate::core::DocContext;
 use crate::fold::DocFolder;
diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs
index 1bea93c7842..1cf80a0d80c 100644
--- a/src/librustdoc/passes/stripper.rs
+++ b/src/librustdoc/passes/stripper.rs
@@ -1,4 +1,5 @@
 //! A collection of utility functions for the `strip_*` passes.
+
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::{TyCtxt, Visibility};
 use std::mem;
diff --git a/src/librustdoc/visit.rs b/src/librustdoc/visit.rs
index 0660037e4d8..b335dc5bd16 100644
--- a/src/librustdoc/visit.rs
+++ b/src/librustdoc/visit.rs
@@ -33,8 +33,8 @@ pub(crate) trait DocVisitor: Sized {
             | TyMethodItem(_)
             | MethodItem(_, _)
             | StructFieldItem(_)
-            | ForeignFunctionItem(_)
-            | ForeignStaticItem(_)
+            | ForeignFunctionItem(..)
+            | ForeignStaticItem(..)
             | ForeignTypeItem
             | MacroItem(_)
             | ProcMacroItem(_)
diff --git a/src/llvm-project b/src/llvm-project
-Subproject 5a5152f653959d14d68613a3a8a033fb65eec02
+Subproject c54cff0e6e4d1a0d0a2df7c1ce3d96cdd554763
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index 68030493e9c..89115d4d7d6 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
 use std::path::PathBuf;
 
 /// rustdoc format-version.
-pub const FORMAT_VERSION: u32 = 30;
+pub const FORMAT_VERSION: u32 = 31;
 
 /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
 /// about the language items in the local crate, as well as info about external items to allow
@@ -511,9 +511,9 @@ pub enum WherePredicate {
         /// ```
         generic_params: Vec<GenericParamDef>,
     },
-    RegionPredicate {
+    LifetimePredicate {
         lifetime: String,
-        bounds: Vec<GenericBound>,
+        outlives: Vec<String>,
     },
     EqPredicate {
         lhs: Type,
diff --git a/src/tools/build-manifest/README.md b/src/tools/build-manifest/README.md
index 9d30c554186..2ea1bffb35f 100644
--- a/src/tools/build-manifest/README.md
+++ b/src/tools/build-manifest/README.md
@@ -4,7 +4,7 @@ This tool generates the manifests uploaded to static.rust-lang.org and used by r
 You can see a full list of all manifests at <https://static.rust-lang.org/manifests.txt>.
 This listing is updated by <https://github.com/rust-lang/generate-manifest-list> every 7 days.
 
-This gets called by `promote-release` <https://github.com/rust-lang/promote-release> via `x.py dist hash-and-sign`.
+This gets called by `promote-release` <https://github.com/rust-lang/promote-release>. `promote-release` downloads a pre-built binary of `build-manifest` which is generated in the dist-x86_64-linux builder and uploaded to s3.
 
 ## Adding a new component
 
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index a709aab7ce2..a2e7907b532 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -25,6 +25,7 @@ static HOSTS: &[&str] = &[
     "i686-pc-windows-msvc",
     "i686-unknown-linux-gnu",
     "loongarch64-unknown-linux-gnu",
+    "loongarch64-unknown-linux-musl",
     "mips-unknown-linux-gnu",
     "mips64-unknown-linux-gnuabi64",
     "mips64el-unknown-linux-gnuabi64",
@@ -106,6 +107,7 @@ static TARGETS: &[&str] = &[
     "i686-unknown-redox",
     "i686-unknown-uefi",
     "loongarch64-unknown-linux-gnu",
+    "loongarch64-unknown-linux-musl",
     "loongarch64-unknown-none",
     "loongarch64-unknown-none-softfloat",
     "m68k-unknown-linux-gnu",
diff --git a/src/tools/build_helper/src/util.rs b/src/tools/build_helper/src/util.rs
index 5801a8648f2..72c05c4c48a 100644
--- a/src/tools/build_helper/src/util.rs
+++ b/src/tools/build_helper/src/util.rs
@@ -1,4 +1,8 @@
+use std::fs::File;
+use std::io::{BufRead, BufReader};
+use std::path::Path;
 use std::process::Command;
+use std::sync::OnceLock;
 
 /// Invokes `build_helper::util::detail_exit` with `cfg!(test)`
 ///
@@ -45,3 +49,27 @@ pub fn try_run(cmd: &mut Command, print_cmd_on_fail: bool) -> Result<(), ()> {
         Ok(())
     }
 }
+
+/// Returns the submodule paths from the `.gitmodules` file in the given directory.
+pub fn parse_gitmodules(target_dir: &Path) -> &[String] {
+    static SUBMODULES_PATHS: OnceLock<Vec<String>> = OnceLock::new();
+    let gitmodules = target_dir.join(".gitmodules");
+    assert!(gitmodules.exists(), "'{}' file is missing.", gitmodules.display());
+
+    let init_submodules_paths = || {
+        let file = File::open(gitmodules).unwrap();
+
+        let mut submodules_paths = vec![];
+        for line in BufReader::new(file).lines().map_while(Result::ok) {
+            let line = line.trim();
+            if line.starts_with("path") {
+                let actual_path = line.split(' ').last().expect("Couldn't get value of path");
+                submodules_paths.push(actual_path.to_owned());
+            }
+        }
+
+        submodules_paths
+    };
+
+    SUBMODULES_PATHS.get_or_init(|| init_submodules_paths())
+}
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 3ed207e416fb2f678a40cc79c02dcf4f936a21c
+Subproject 154fdac39ae9629954e19e9986fd2cf2cdd8d96
diff --git a/src/tools/clippy/.github/workflows/lintcheck.yml b/src/tools/clippy/.github/workflows/lintcheck.yml
new file mode 100644
index 00000000000..91c98b3a256
--- /dev/null
+++ b/src/tools/clippy/.github/workflows/lintcheck.yml
@@ -0,0 +1,118 @@
+name: Lintcheck
+
+on: pull_request
+
+env:
+  RUST_BACKTRACE: 1
+  CARGO_INCREMENTAL: 0
+
+concurrency:
+  # For a given workflow, if we push to the same PR, cancel all previous builds on that PR.
+  group: "${{ github.workflow }}-${{ github.event.pull_request.number}}"
+  cancel-in-progress: true
+
+jobs:
+  # Runs lintcheck on the PR's target branch and stores the results as an artifact
+  base:
+    runs-on: ubuntu-latest
+
+    steps:
+    - name: Checkout
+      uses: actions/checkout@v4
+      with:
+        fetch-depth: 2
+
+    # HEAD is the generated merge commit `refs/pull/N/merge` between the PR and `master`, `HEAD^`
+    # being the commit from `master` that is the base of the merge
+    - name: Checkout base
+      run: git checkout HEAD^
+
+    # Use the lintcheck from the PR to generate the JSON in case the PR modifies lintcheck in some
+    # way
+    - name: Checkout current lintcheck
+      run: |
+        rm -rf lintcheck
+        git checkout ${{ github.sha }} -- lintcheck
+
+    - name: Cache lintcheck bin
+      id: cache-lintcheck-bin
+      uses: actions/cache@v4
+      with:
+        path: target/debug/lintcheck
+        key: lintcheck-bin-${{ hashfiles('lintcheck/**') }}
+
+    - name: Build lintcheck
+      if: steps.cache-lintcheck-bin.outputs.cache-hit != 'true'
+      run: cargo build --manifest-path=lintcheck/Cargo.toml
+
+    - name: Create cache key
+      id: key
+      run: echo "key=lintcheck-base-${{ hashfiles('lintcheck/**') }}-$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
+
+    - name: Cache results JSON
+      id: cache-json
+      uses: actions/cache@v4
+      with:
+        path: lintcheck-logs/lintcheck_crates_logs.json
+        key: ${{ steps.key.outputs.key }}
+
+    - name: Run lintcheck
+      if: steps.cache-json.outputs.cache-hit != 'true'
+      run: ./target/debug/lintcheck --format json
+
+    - name: Upload base JSON
+      uses: actions/upload-artifact@v4
+      with:
+        name: base
+        path: lintcheck-logs/lintcheck_crates_logs.json
+
+  # Runs lintcheck on the PR and stores the results as an artifact
+  head:
+    runs-on: ubuntu-latest
+
+    steps:
+    - name: Checkout
+      uses: actions/checkout@v4
+
+    - name: Cache lintcheck bin
+      id: cache-lintcheck-bin
+      uses: actions/cache@v4
+      with:
+        path: target/debug/lintcheck
+        key: lintcheck-bin-${{ hashfiles('lintcheck/**') }}
+
+    - name: Build lintcheck
+      if: steps.cache-lintcheck-bin.outputs.cache-hit != 'true'
+      run: cargo build --manifest-path=lintcheck/Cargo.toml
+
+    - name: Run lintcheck
+      run: ./target/debug/lintcheck --format json
+
+    - name: Upload head JSON
+      uses: actions/upload-artifact@v4
+      with:
+        name: head
+        path: lintcheck-logs/lintcheck_crates_logs.json
+
+  # Retrieves the head and base JSON results and prints the diff to the GH actions step summary
+  diff:
+    runs-on: ubuntu-latest
+
+    needs: [base, head]
+
+    steps:
+    - name: Checkout
+      uses: actions/checkout@v4
+
+    - name: Restore lintcheck bin
+      uses: actions/cache/restore@v4
+      with:
+        path: target/debug/lintcheck
+        key: lintcheck-bin-${{ hashfiles('lintcheck/**') }}
+        fail-on-cache-miss: true
+
+    - name: Download JSON
+      uses: actions/download-artifact@v4
+
+    - name: Diff results
+      run: ./target/debug/lintcheck diff {base,head}/lintcheck_crates_logs.json >> $GITHUB_STEP_SUMMARY
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index d7bcd7a1968..70ef2c79364 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -1943,7 +1943,7 @@ Released 2022-05-19
   [#8218](https://github.com/rust-lang/rust-clippy/pull/8218)
 * [`needless_match`]
   [#8471](https://github.com/rust-lang/rust-clippy/pull/8471)
-* [`allow_attributes_without_reason`] (Requires `#![feature(lint_reasons)]`)
+* [`allow_attributes_without_reason`]
   [#8504](https://github.com/rust-lang/rust-clippy/pull/8504)
 * [`print_in_format_impl`]
   [#8253](https://github.com/rust-lang/rust-clippy/pull/8253)
@@ -5362,6 +5362,7 @@ Released 2018-09-13
 [`extra_unused_type_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#extra_unused_type_parameters
 [`fallible_impl_from`]: https://rust-lang.github.io/rust-clippy/master/index.html#fallible_impl_from
 [`field_reassign_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#field_reassign_with_default
+[`field_scoped_visibility_modifiers`]: https://rust-lang.github.io/rust-clippy/master/index.html#field_scoped_visibility_modifiers
 [`filetype_is_file`]: https://rust-lang.github.io/rust-clippy/master/index.html#filetype_is_file
 [`filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map
 [`filter_map_bool_then`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_bool_then
@@ -5520,6 +5521,7 @@ Released 2018-09-13
 [`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map
 [`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten
 [`manual_hash_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one
+[`manual_inspect`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_inspect
 [`manual_instant_elapsed`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_instant_elapsed
 [`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check
 [`manual_is_finite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_finite
@@ -5915,6 +5917,7 @@ Released 2018-09-13
 [`unnecessary_lazy_evaluations`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations
 [`unnecessary_literal_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_literal_unwrap
 [`unnecessary_map_on_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_map_on_constructor
+[`unnecessary_min_or_max`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_min_or_max
 [`unnecessary_mut_passed`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed
 [`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation
 [`unnecessary_owned_empty_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_owned_empty_strings
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index c8223007df7..cfd34c7d2a7 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -454,7 +454,7 @@ default configuration of Clippy. By default, any configuration will replace the
 * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`.
 * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list.
 
-**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "WebGL", "WebGL2", "WebGPU", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]`
+**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DevOps", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "WebGL", "WebGL2", "WebGPU", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]`
 
 ---
 **Affected lints:**
@@ -669,6 +669,8 @@ The minimum rust version that the project supports. Defaults to the `rust-versio
 
 ---
 **Affected lints:**
+* [`allow_attributes`](https://rust-lang.github.io/rust-clippy/master/index.html#allow_attributes)
+* [`allow_attributes_without_reason`](https://rust-lang.github.io/rust-clippy/master/index.html#allow_attributes_without_reason)
 * [`almost_complete_range`](https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_range)
 * [`approx_constant`](https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant)
 * [`assigning_clones`](https://rust-lang.github.io/rust-clippy/master/index.html#assigning_clones)
@@ -693,6 +695,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio
 * [`manual_is_ascii_check`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check)
 * [`manual_let_else`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else)
 * [`manual_non_exhaustive`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive)
+* [`manual_pattern_char_comparison`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_pattern_char_comparison)
 * [`manual_range_contains`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains)
 * [`manual_rem_euclid`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid)
 * [`manual_retain`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain)
diff --git a/src/tools/clippy/book/src/usage.md b/src/tools/clippy/book/src/usage.md
index 36448e4cccf..7a0be6994fe 100644
--- a/src/tools/clippy/book/src/usage.md
+++ b/src/tools/clippy/book/src/usage.md
@@ -36,7 +36,7 @@ You can configure lint levels on the command line by adding
 cargo clippy -- -Aclippy::style -Wclippy::double_neg -Dclippy::perf
 ```
 
-For [CI] all warnings can be elevated to errors which will inturn fail
+For [CI] all warnings can be elevated to errors which will in turn fail
 the build and cause Clippy to exit with a code other than `0`.
 
 ```
diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs
index cfdf620b7d0..dbab3b106a8 100644
--- a/src/tools/clippy/clippy_config/src/conf.rs
+++ b/src/tools/clippy/clippy_config/src/conf.rs
@@ -18,6 +18,7 @@ use std::{cmp, env, fmt, fs, io};
 #[rustfmt::skip]
 const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[
     "KiB", "MiB", "GiB", "TiB", "PiB", "EiB",
+    "DevOps",
     "DirectX",
     "ECMAScript",
     "GPLv2", "GPLv3",
@@ -265,7 +266,7 @@ define_Conf! {
     ///
     /// Suppress lints whenever the suggested change would cause breakage for other crates.
     (avoid_breaking_exported_api: bool = true),
-    /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE, ITER_KV_MAP, MANUAL_C_STR_LITERALS, ASSIGNING_CLONES, LEGACY_NUMERIC_CONSTANTS.
+    /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE, ITER_KV_MAP, MANUAL_C_STR_LITERALS, ASSIGNING_CLONES, LEGACY_NUMERIC_CONSTANTS, MANUAL_PATTERN_CHAR_COMPARISON, ALLOW_ATTRIBUTES, ALLOW_ATTRIBUTES_WITHOUT_REASON.
     ///
     /// The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml`
     #[default_text = ""]
diff --git a/src/tools/clippy/clippy_config/src/msrvs.rs b/src/tools/clippy/clippy_config/src/msrvs.rs
index a3e7d0c3fa5..a5761d3270c 100644
--- a/src/tools/clippy/clippy_config/src/msrvs.rs
+++ b/src/tools/clippy/clippy_config/src/msrvs.rs
@@ -17,8 +17,9 @@ macro_rules! msrv_aliases {
 
 // names may refer to stabilized feature flags or library items
 msrv_aliases! {
+    1,81,0  { LINT_REASONS_STABILIZATION }
     1,77,0 { C_STR_LITERALS }
-    1,76,0 { PTR_FROM_REF }
+    1,76,0 { PTR_FROM_REF, OPTION_RESULT_INSPECT }
     1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE }
     1,70,0 { OPTION_RESULT_IS_VARIANT_AND, BINARY_HEAP_RETAIN }
     1,68,0 { PATH_MAIN_SEPARATOR_STR }
diff --git a/src/tools/clippy/clippy_lints/src/allow_attributes.rs b/src/tools/clippy/clippy_lints/src/allow_attributes.rs
deleted file mode 100644
index 123d0e51eee..00000000000
--- a/src/tools/clippy/clippy_lints/src/allow_attributes.rs
+++ /dev/null
@@ -1,74 +0,0 @@
-use ast::{AttrStyle, Attribute};
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_from_proc_macro;
-use rustc_ast as ast;
-use rustc_errors::Applicability;
-use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
-use rustc_session::declare_lint_pass;
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for usage of the `#[allow]` attribute and suggests replacing it with
-    /// the `#[expect]` (See [RFC 2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html))
-    ///
-    /// The expect attribute is still unstable and requires the `lint_reasons`
-    /// on nightly. It can be enabled by adding `#![feature(lint_reasons)]` to
-    /// the crate root.
-    ///
-    /// This lint only warns outer attributes (`#[allow]`), as inner attributes
-    /// (`#![allow]`) are usually used to enable or disable lints on a global scale.
-    ///
-    /// ### Why restrict this?
-    /// `#[allow]` attributes can linger after their reason for existence is gone.
-    /// `#[expect]` attributes suppress the lint emission, but emit a warning if
-    /// the expectation is unfulfilled. This can be useful to be notified when the
-    /// lint is no longer triggered, which may indicate the attribute can be removed.
-    ///
-    /// ### Example
-    /// ```rust,ignore
-    /// #[allow(unused_mut)]
-    /// fn foo() -> usize {
-    ///    let mut a = Vec::new();
-    ///    a.len()
-    /// }
-    /// ```
-    /// Use instead:
-    /// ```rust,ignore
-    /// #![feature(lint_reasons)]
-    /// #[expect(unused_mut)]
-    /// fn foo() -> usize {
-    ///     let mut a = Vec::new();
-    ///     a.len()
-    /// }
-    /// ```
-    #[clippy::version = "1.70.0"]
-    pub ALLOW_ATTRIBUTES,
-    restriction,
-    "`#[allow]` will not trigger if a warning isn't found. `#[expect]` triggers if there are no warnings."
-}
-
-declare_lint_pass!(AllowAttribute => [ALLOW_ATTRIBUTES]);
-
-impl LateLintPass<'_> for AllowAttribute {
-    // Separate each crate's features.
-    fn check_attribute<'cx>(&mut self, cx: &LateContext<'cx>, attr: &'cx Attribute) {
-        if !in_external_macro(cx.sess(), attr.span)
-            && cx.tcx.features().lint_reasons
-            && let AttrStyle::Outer = attr.style
-            && let Some(ident) = attr.ident()
-            && ident.name == rustc_span::symbol::sym::allow
-            && !is_from_proc_macro(cx, &attr)
-        {
-            span_lint_and_sugg(
-                cx,
-                ALLOW_ATTRIBUTES,
-                ident.span,
-                "#[allow] attribute found",
-                "replace it with",
-                "expect".into(),
-                Applicability::MachineApplicable,
-            );
-        }
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs
index 38933897389..d57ab539fff 100644
--- a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs
+++ b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs
@@ -17,7 +17,7 @@ declare_clippy_lint! {
     /// `Arc<T>` is a thread-safe `Rc<T>` and guarantees that updates to the reference counter
     /// use atomic operations. To send an `Arc<T>` across thread boundaries and
     /// share ownership between multiple threads, `T` must be [both `Send` and `Sync`](https://doc.rust-lang.org/std/sync/struct.Arc.html#thread-safety),
-    /// so either `T` should be made `Send + Sync` or an `Rc` should be used instead of an `Arc`
+    /// so either `T` should be made `Send + Sync` or an `Rc` should be used instead of an `Arc`.
     ///
     /// ### Example
     /// ```no_run
diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
index e94a6f3e3fc..406f38f411e 100644
--- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs
+++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
@@ -1,16 +1,18 @@
 use clippy_config::msrvs::{self, Msrv};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::HirNode;
+use clippy_utils::mir::{enclosing_mir, PossibleBorrowerMap};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{is_trait_method, local_is_initialized, path_to_local};
 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::def_id::DefId;
 use rustc_span::symbol::sym;
-use rustc_span::{ExpnKind, SyntaxContext};
+use rustc_span::{ExpnKind, Span, SyntaxContext};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -101,7 +103,7 @@ fn extract_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<
             let args = cx.typeck_results().node_args(expr.hir_id);
 
             // If we could not resolve the method, don't apply the lint
-            let Ok(Some(resolved_method)) = Instance::resolve(cx.tcx, cx.param_env, fn_def_id, args) else {
+            let Ok(Some(resolved_method)) = Instance::try_resolve(cx.tcx, cx.param_env, fn_def_id, args) else {
                 return None;
             };
             if is_trait_method(cx, expr, sym::Clone) && path.ident.name == sym::clone {
@@ -117,7 +119,7 @@ fn extract_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<
 
             // If we could not resolve the method, don't apply the lint
             let Ok(Some(resolved_method)) = (match kind {
-                ty::FnDef(_, args) => Instance::resolve(cx.tcx, cx.param_env, fn_def_id, args),
+                ty::FnDef(_, args) => Instance::try_resolve(cx.tcx, cx.param_env, fn_def_id, args),
                 _ => Ok(None),
             }) else {
                 return None;
@@ -144,6 +146,7 @@ fn extract_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<
     };
 
     Some(CallCandidate {
+        span: expr.span,
         target,
         kind,
         method_def_id: resolved_method.def_id(),
@@ -215,6 +218,10 @@ fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallC
         return false;
     };
 
+    if clone_source_borrows_from_dest(cx, lhs, call.span) {
+        return false;
+    }
+
     // Now take a look if the impl block defines an implementation for the method that we're interested
     // in. If not, then we're using a default implementation, which is not interesting, so we will
     // not suggest the lint.
@@ -222,6 +229,74 @@ fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallC
     implemented_fns.contains_key(&provided_fn.def_id)
 }
 
+/// Checks if the data being cloned borrows from the place that is being assigned to:
+///
+/// ```
+/// let mut s = String::new();
+/// let s2 = &s;
+/// s = s2.to_owned();
+/// ```
+///
+/// This cannot be written `s2.clone_into(&mut s)` because it has conflicting borrows.
+fn clone_source_borrows_from_dest(cx: &LateContext<'_>, lhs: &Expr<'_>, call_span: Span) -> bool {
+    /// If this basic block only exists to drop a local as part of an assignment, returns its
+    /// successor. Otherwise returns the basic block that was passed in.
+    fn skip_drop_block(mir: &mir::Body<'_>, bb: mir::BasicBlock) -> mir::BasicBlock {
+        if let mir::TerminatorKind::Drop { target, .. } = mir.basic_blocks[bb].terminator().kind {
+            target
+        } else {
+            bb
+        }
+    }
+
+    let Some(mir) = enclosing_mir(cx.tcx, lhs.hir_id) else {
+        return false;
+    };
+    let PossibleBorrowerMap { map: borrow_map, .. } = PossibleBorrowerMap::new(cx, mir);
+
+    // The operation `dest = src.to_owned()` in MIR is split up across 3 blocks *if* the type has `Drop`
+    // code. For types that don't, the second basic block is simply skipped.
+    // For the doc example above that would be roughly:
+    //
+    // bb0:
+    //  s2 = &s
+    //  s_temp = ToOwned::to_owned(move s2) -> bb1
+    //
+    // bb1:
+    //  drop(s) -> bb2  // drop the old string
+    //
+    // bb2:
+    //  s = s_temp
+    for bb in mir.basic_blocks.iter() {
+        let terminator = bb.terminator();
+
+        // Look for the to_owned/clone call.
+        if terminator.source_info.span != call_span {
+            continue;
+        }
+
+        if let mir::TerminatorKind::Call { ref args, target: Some(assign_bb), .. } = terminator.kind
+            && let [source] = &**args
+            && let mir::Operand::Move(source) = &source.node
+            && let assign_bb = skip_drop_block(mir, assign_bb)
+            // Skip any storage statements as they are just noise
+            && let Some(assignment) = mir.basic_blocks[assign_bb].statements
+                .iter()
+                .find(|stmt| {
+                    !matches!(stmt.kind, mir::StatementKind::StorageDead(_) | mir::StatementKind::StorageLive(_))
+                })
+            && let mir::StatementKind::Assign(box (borrowed, _)) = &assignment.kind
+            && let Some(borrowers) = borrow_map.get(&borrowed.local)
+            && borrowers.contains(source.local)
+        {
+            return true;
+        }
+
+        return false;
+    }
+    false
+}
+
 fn suggest<'tcx>(
     cx: &LateContext<'tcx>,
     ctxt: SyntaxContext,
@@ -255,6 +330,7 @@ enum TargetTrait {
 
 #[derive(Debug)]
 struct CallCandidate<'tcx> {
+    span: Span,
     target: TargetTrait,
     kind: CallKind<'tcx>,
     // DefId of the called method from an impl block that implements the target trait
diff --git a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs
new file mode 100644
index 00000000000..df9994086cd
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs
@@ -0,0 +1,26 @@
+use super::ALLOW_ATTRIBUTES;
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_from_proc_macro;
+use rustc_ast::{AttrStyle, Attribute};
+use rustc_errors::Applicability;
+use rustc_lint::{LateContext, LintContext};
+use rustc_middle::lint::in_external_macro;
+
+// Separate each crate's features.
+pub fn check<'cx>(cx: &LateContext<'cx>, attr: &'cx Attribute) {
+    if !in_external_macro(cx.sess(), attr.span)
+        && let AttrStyle::Outer = attr.style
+        && let Some(ident) = attr.ident()
+        && !is_from_proc_macro(cx, attr)
+    {
+        span_lint_and_sugg(
+            cx,
+            ALLOW_ATTRIBUTES,
+            ident.span,
+            "#[allow] attribute found",
+            "replace it with",
+            "expect".into(),
+            Applicability::MachineApplicable,
+        );
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs
index 4a22e17463f..4b42616a636 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs
@@ -8,11 +8,6 @@ use rustc_span::sym;
 use rustc_span::symbol::Symbol;
 
 pub(super) fn check<'cx>(cx: &LateContext<'cx>, name: Symbol, items: &[NestedMetaItem], attr: &'cx Attribute) {
-    // Check for the feature
-    if !cx.tcx.features().lint_reasons {
-        return;
-    }
-
     // Check if the reason is present
     if let Some(item) = items.last().and_then(NestedMetaItem::meta_item)
         && let MetaItemKind::NameValue(_) = &item.kind
@@ -22,7 +17,7 @@ pub(super) fn check<'cx>(cx: &LateContext<'cx>, name: Symbol, items: &[NestedMet
     }
 
     // Check if the attribute is in an external macro and therefore out of the developer's control
-    if in_external_macro(cx.sess(), attr.span) || is_from_proc_macro(cx, &attr) {
+    if in_external_macro(cx.sess(), attr.span) || is_from_proc_macro(cx, attr) {
         return;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs
index e4c98a32fd6..8ec60314cc9 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs
@@ -1,5 +1,6 @@
 //! checks for attributes
 
+mod allow_attributes;
 mod allow_attributes_without_reason;
 mod blanket_clippy_restriction_lints;
 mod deprecated_cfg_attr;
@@ -14,11 +15,11 @@ mod unnecessary_clippy_cfg;
 mod useless_attribute;
 mod utils;
 
-use clippy_config::msrvs::Msrv;
+use clippy_config::msrvs::{self, Msrv};
 use rustc_ast::{Attribute, MetaItemKind, NestedMetaItem};
 use rustc_hir::{ImplItem, Item, ItemKind, TraitItem};
 use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, impl_lint_pass};
+use rustc_session::impl_lint_pass;
 use rustc_span::sym;
 use utils::{is_lint_level, is_relevant_impl, is_relevant_item, is_relevant_trait};
 
@@ -272,23 +273,17 @@ declare_clippy_lint! {
     /// ### What it does
     /// Checks for attributes that allow lints without a reason.
     ///
-    /// (This requires the `lint_reasons` feature)
-    ///
     /// ### Why restrict this?
     /// Justifying each `allow` helps readers understand the reasoning,
     /// and may allow removing `allow` attributes if their purpose is obsolete.
     ///
     /// ### Example
     /// ```no_run
-    /// #![feature(lint_reasons)]
-    ///
     /// #![allow(clippy::some_lint)]
     /// ```
     ///
     /// Use instead:
     /// ```no_run
-    /// #![feature(lint_reasons)]
-    ///
     /// #![allow(clippy::some_lint, reason = "False positive rust-lang/rust-clippy#1002020")]
     /// ```
     #[clippy::version = "1.61.0"]
@@ -299,6 +294,41 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
+    /// Checks for usage of the `#[allow]` attribute and suggests replacing it with
+    /// the `#[expect]` (See [RFC 2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html))
+    ///
+    /// This lint only warns outer attributes (`#[allow]`), as inner attributes
+    /// (`#![allow]`) are usually used to enable or disable lints on a global scale.
+    ///
+    /// ### Why is this bad?
+    /// `#[expect]` attributes suppress the lint emission, but emit a warning, if
+    /// the expectation is unfulfilled. This can be useful to be notified when the
+    /// lint is no longer triggered.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// #[allow(unused_mut)]
+    /// fn foo() -> usize {
+    ///    let mut a = Vec::new();
+    ///    a.len()
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// #[expect(unused_mut)]
+    /// fn foo() -> usize {
+    ///     let mut a = Vec::new();
+    ///     a.len()
+    /// }
+    /// ```
+    #[clippy::version = "1.70.0"]
+    pub ALLOW_ATTRIBUTES,
+    restriction,
+    "`#[allow]` will not trigger if a warning isn't found. `#[expect]` triggers if there are no warnings."
+}
+
+declare_clippy_lint! {
+    /// ### What it does
     /// Checks for `#[should_panic]` attributes without specifying the expected panic message.
     ///
     /// ### Why is this bad?
@@ -469,7 +499,13 @@ declare_clippy_lint! {
     "duplicated attribute"
 }
 
-declare_lint_pass!(Attributes => [
+#[derive(Clone)]
+pub struct Attributes {
+    msrv: Msrv,
+}
+
+impl_lint_pass!(Attributes => [
+    ALLOW_ATTRIBUTES,
     ALLOW_ATTRIBUTES_WITHOUT_REASON,
     INLINE_ALWAYS,
     DEPRECATED_SEMVER,
@@ -480,6 +516,13 @@ declare_lint_pass!(Attributes => [
     DUPLICATED_ATTRIBUTES,
 ]);
 
+impl Attributes {
+    #[must_use]
+    pub fn new(msrv: Msrv) -> Self {
+        Self { msrv }
+    }
+}
+
 impl<'tcx> LateLintPass<'tcx> for Attributes {
     fn check_crate(&mut self, cx: &LateContext<'tcx>) {
         blanket_clippy_restriction_lints::check_command_line(cx);
@@ -492,7 +535,11 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
                 if is_lint_level(ident.name, attr.id) {
                     blanket_clippy_restriction_lints::check(cx, ident.name, items);
                 }
-                if matches!(ident.name, sym::allow | sym::expect) {
+                if matches!(ident.name, sym::allow) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) {
+                    allow_attributes::check(cx, attr);
+                }
+                if matches!(ident.name, sym::allow | sym::expect) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION)
+                {
                     allow_attributes_without_reason::check(cx, ident.name, items, attr);
                 }
                 if items.is_empty() || !attr.has_name(sym::deprecated) {
@@ -537,6 +584,8 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
             inline_always::check(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id()));
         }
     }
+
+    extract_msrv_attr!(LateContext);
 }
 
 pub struct EarlyAttributes {
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 58c1a2f2706..db5792188dd 100644
--- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
+++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
@@ -61,7 +61,7 @@ fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -
             )
         })
         .map_or(false, |assoc_item| {
-            let proj = Ty::new_projection(cx.tcx, assoc_item.def_id, cx.tcx.mk_args_trait(ty, []));
+            let proj = Ty::new_projection_from_args(cx.tcx, assoc_item.def_id, cx.tcx.mk_args_trait(ty, []));
             let nty = cx.tcx.normalize_erasing_regions(cx.param_env, proj);
 
             nty.is_bool()
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs b/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs
index 1743ce71add..5bc8692c289 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs
@@ -21,6 +21,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
 
 fn is_known_nan(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
     match constant(cx, cx.typeck_results(), e) {
+        // FIXME(f16_f128): add these types when nan checks are available on all platforms
         Some(Constant::F64(n)) => n.is_nan(),
         Some(Constant::F32(n)) => n.is_nan(),
         _ => false,
diff --git a/src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs
index f42bafce4dd..5f48b8bd206 100644
--- a/src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs
@@ -22,9 +22,9 @@ pub(super) fn check<'tcx>(
 
     if matches!(cast_from.kind(), ty::Ref(..))
         && let ty::RawPtr(_, to_mutbl) = cast_to.kind()
-        && let Some(use_cx) = expr_use_ctxt(cx, expr)
+        && let use_cx = expr_use_ctxt(cx, expr)
         // TODO: only block the lint if `cast_expr` is a temporary
-        && !matches!(use_cx.node, ExprUseNode::LetStmt(_) | ExprUseNode::ConstStatic(_))
+        && !matches!(use_cx.use_node(cx), ExprUseNode::LetStmt(_) | ExprUseNode::ConstStatic(_))
     {
         let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" };
         let fn_name = match to_mutbl {
diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
index e41abf42234..60815f4f2af 100644
--- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
+++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
@@ -1,7 +1,7 @@
 //! calculate cognitive complexity and warn about overly complex functions
 
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::source::snippet_opt;
+use clippy_utils::source::{IntoSpan, SpanRangeExt};
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::for_each_expr_without_closures;
 use clippy_utils::{get_async_fn_body, is_async_fn, LimitStack};
@@ -12,7 +12,7 @@ use rustc_hir::{Body, Expr, ExprKind, FnDecl};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::impl_lint_pass;
 use rustc_span::def_id::LocalDefId;
-use rustc_span::{sym, BytePos, Span};
+use rustc_span::{sym, Span};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -50,7 +50,6 @@ impl CognitiveComplexity {
 impl_lint_pass!(CognitiveComplexity => [COGNITIVE_COMPLEXITY]);
 
 impl CognitiveComplexity {
-    #[expect(clippy::cast_possible_truncation)]
     fn check<'tcx>(
         &mut self,
         cx: &LateContext<'tcx>,
@@ -100,17 +99,12 @@ impl CognitiveComplexity {
                 FnKind::ItemFn(ident, _, _) | FnKind::Method(ident, _) => ident.span,
                 FnKind::Closure => {
                     let header_span = body_span.with_hi(decl.output.span().lo());
-                    let pos = snippet_opt(cx, header_span).and_then(|snip| {
-                        let low_offset = snip.find('|')?;
-                        let high_offset = 1 + snip.get(low_offset + 1..)?.find('|')?;
-                        let low = header_span.lo() + BytePos(low_offset as u32);
-                        let high = low + BytePos(high_offset as u32 + 1);
-
-                        Some((low, high))
-                    });
-
-                    if let Some((low, high)) = pos {
-                        Span::new(low, high, header_span.ctxt(), header_span.parent())
+                    #[expect(clippy::range_plus_one)]
+                    if let Some(range) = header_span.map_range(cx, |src, range| {
+                        let mut idxs = src.get(range.clone())?.match_indices('|');
+                        Some(range.start + idxs.next()?.0..range.start + idxs.next()?.0 + 1)
+                    }) {
+                        range.with_ctxt(header_span.ctxt())
                     } else {
                         return;
                     }
diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs
index 480df675d75..d896452be92 100644
--- a/src/tools/clippy/clippy_lints/src/copies.rs
+++ b/src/tools/clippy/clippy_lints/src/copies.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then};
-use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, snippet_opt};
+use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, IntoSpan, SpanRangeExt};
 use clippy_utils::ty::{needs_ordered_drop, InteriorMut};
 use clippy_utils::visitors::for_each_expr_without_closures;
 use clippy_utils::{
@@ -14,7 +14,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
 use rustc_span::hygiene::walk_chain;
 use rustc_span::source_map::SourceMap;
-use rustc_span::{BytePos, Span, Symbol};
+use rustc_span::{Span, Symbol};
 use std::borrow::Cow;
 
 declare_clippy_lint! {
@@ -266,12 +266,12 @@ fn lint_branches_sharing_code<'tcx>(
 
         let span = span.with_hi(last_block.span.hi());
         // Improve formatting if the inner block has indention (i.e. normal Rust formatting)
-        let test_span = Span::new(span.lo() - BytePos(4), span.lo(), span.ctxt(), span.parent());
-        let span = if snippet_opt(cx, test_span).map_or(false, |snip| snip == "    ") {
-            span.with_lo(test_span.lo())
-        } else {
-            span
-        };
+        let span = span
+            .map_range(cx, |src, range| {
+                (range.start > 4 && src.get(range.start - 4..range.start)? == "    ")
+                    .then_some(range.start - 4..range.end)
+            })
+            .map_or(span, |range| range.with_ctxt(span.ctxt()));
         (span, suggestion.to_string())
     });
 
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 7e43a99e9f2..638de5e818c 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -38,7 +38,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     #[cfg(feature = "internal")]
     crate::utils::internal_lints::unsorted_clippy_utils_paths::UNSORTED_CLIPPY_UTILS_PATHS_INFO,
     crate::absolute_paths::ABSOLUTE_PATHS_INFO,
-    crate::allow_attributes::ALLOW_ATTRIBUTES_INFO,
     crate::almost_complete_range::ALMOST_COMPLETE_RANGE_INFO,
     crate::approx_const::APPROX_CONSTANT_INFO,
     crate::arc_with_non_send_sync::ARC_WITH_NON_SEND_SYNC_INFO,
@@ -49,6 +48,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES_INFO,
     crate::assigning_clones::ASSIGNING_CLONES_INFO,
     crate::async_yields_async::ASYNC_YIELDS_ASYNC_INFO,
+    crate::attrs::ALLOW_ATTRIBUTES_INFO,
     crate::attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON_INFO,
     crate::attrs::BLANKET_CLIPPY_RESTRICTION_LINTS_INFO,
     crate::attrs::DEPRECATED_CFG_ATTR_INFO,
@@ -178,6 +178,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::explicit_write::EXPLICIT_WRITE_INFO,
     crate::extra_unused_type_parameters::EXTRA_UNUSED_TYPE_PARAMETERS_INFO,
     crate::fallible_impl_from::FALLIBLE_IMPL_FROM_INFO,
+    crate::field_scoped_visibility_modifiers::FIELD_SCOPED_VISIBILITY_MODIFIERS_INFO,
     crate::float_literal::EXCESSIVE_PRECISION_INFO,
     crate::float_literal::LOSSY_FLOAT_LITERAL_INFO,
     crate::floating_point_arithmetic::IMPRECISE_FLOPS_INFO,
@@ -402,6 +403,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::methods::MANUAL_C_STR_LITERALS_INFO,
     crate::methods::MANUAL_FILTER_MAP_INFO,
     crate::methods::MANUAL_FIND_MAP_INFO,
+    crate::methods::MANUAL_INSPECT_INFO,
     crate::methods::MANUAL_IS_VARIANT_AND_INFO,
     crate::methods::MANUAL_NEXT_BACK_INFO,
     crate::methods::MANUAL_OK_OR_INFO,
@@ -469,6 +471,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::methods::UNNECESSARY_JOIN_INFO,
     crate::methods::UNNECESSARY_LAZY_EVALUATIONS_INFO,
     crate::methods::UNNECESSARY_LITERAL_UNWRAP_INFO,
+    crate::methods::UNNECESSARY_MIN_OR_MAX_INFO,
     crate::methods::UNNECESSARY_RESULT_MAP_OR_ELSE_INFO,
     crate::methods::UNNECESSARY_SORT_BY_INFO,
     crate::methods::UNNECESSARY_TO_OWNED_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index d60320d8282..a115f8d0631 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -6,7 +6,7 @@ use clippy_utils::{
     expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, DefinedTy, ExprUseNode,
 };
 use core::mem;
-use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX};
+use rustc_ast::util::parser::{PREC_PREFIX, PREC_UNAMBIGUOUS};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_ty, Visitor};
@@ -260,18 +260,13 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
             (None, kind) => {
                 let expr_ty = typeck.expr_ty(expr);
                 let use_cx = expr_use_ctxt(cx, expr);
-                let adjusted_ty = match &use_cx {
-                    Some(use_cx) => match use_cx.adjustments {
-                        [.., a] => a.target,
-                        _ => expr_ty,
-                    },
-                    _ => typeck.expr_ty_adjusted(expr),
-                };
+                let adjusted_ty = use_cx.adjustments.last().map_or(expr_ty, |a| a.target);
 
-                match (use_cx, kind) {
-                    (Some(use_cx), RefOp::Deref) => {
+                match kind {
+                    RefOp::Deref if use_cx.same_ctxt => {
+                        let use_node = use_cx.use_node(cx);
                         let sub_ty = typeck.expr_ty(sub_expr);
-                        if let ExprUseNode::FieldAccess(name) = use_cx.node
+                        if let ExprUseNode::FieldAccess(name) = use_node
                             && !use_cx.moved_before_use
                             && !ty_contains_field(sub_ty, name.name)
                         {
@@ -288,9 +283,9 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                         } else if sub_ty.is_ref()
                             // Linting method receivers would require verifying that name lookup
                             // would resolve the same way. This is complicated by trait methods.
-                            && !use_cx.node.is_recv()
-                            && let Some(ty) = use_cx.node.defined_ty(cx)
-                            && TyCoercionStability::for_defined_ty(cx, ty, use_cx.node.is_return()).is_deref_stable()
+                            && !use_node.is_recv()
+                            && let Some(ty) = use_node.defined_ty(cx)
+                            && TyCoercionStability::for_defined_ty(cx, ty, use_node.is_return()).is_deref_stable()
                         {
                             self.state = Some((
                                 State::ExplicitDeref { mutability: None },
@@ -301,7 +296,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                             ));
                         }
                     },
-                    (_, RefOp::Method { mutbl, is_ufcs })
+                    RefOp::Method { mutbl, is_ufcs }
                         if !is_lint_allowed(cx, EXPLICIT_DEREF_METHODS, expr.hir_id)
                             // Allow explicit deref in method chains. e.g. `foo.deref().bar()`
                             && (is_ufcs || !in_postfix_position(cx, expr)) =>
@@ -319,7 +314,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                             },
                         ));
                     },
-                    (Some(use_cx), RefOp::AddrOf(mutability)) => {
+                    RefOp::AddrOf(mutability) if use_cx.same_ctxt => {
                         // Find the number of times the borrow is auto-derefed.
                         let mut iter = use_cx.adjustments.iter();
                         let mut deref_count = 0usize;
@@ -338,10 +333,11 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                             };
                         };
 
-                        let stability = use_cx.node.defined_ty(cx).map_or(TyCoercionStability::None, |ty| {
-                            TyCoercionStability::for_defined_ty(cx, ty, use_cx.node.is_return())
+                        let use_node = use_cx.use_node(cx);
+                        let stability = use_node.defined_ty(cx).map_or(TyCoercionStability::None, |ty| {
+                            TyCoercionStability::for_defined_ty(cx, ty, use_node.is_return())
                         });
-                        let can_auto_borrow = match use_cx.node {
+                        let can_auto_borrow = match use_node {
                             ExprUseNode::FieldAccess(_)
                                 if !use_cx.moved_before_use && matches!(sub_expr.kind, ExprKind::Field(..)) =>
                             {
@@ -353,7 +349,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                                 // deref through `ManuallyDrop<_>` will not compile.
                                 !adjust_derefs_manually_drop(use_cx.adjustments, expr_ty)
                             },
-                            ExprUseNode::Callee | ExprUseNode::FieldAccess(_) => true,
+                            ExprUseNode::Callee | ExprUseNode::FieldAccess(_) if !use_cx.moved_before_use => true,
                             ExprUseNode::MethodArg(hir_id, _, 0) if !use_cx.moved_before_use => {
                                 // Check for calls to trait methods where the trait is implemented
                                 // on a reference.
@@ -363,9 +359,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                                 //   priority.
                                 if let Some(fn_id) = typeck.type_dependent_def_id(hir_id)
                                     && let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
-                                    && let arg_ty = cx
-                                        .tcx
-                                        .erase_regions(use_cx.adjustments.last().map_or(expr_ty, |a| a.target))
+                                    && let arg_ty = cx.tcx.erase_regions(adjusted_ty)
                                     && let ty::Ref(_, sub_ty, _) = *arg_ty.kind()
                                     && let args =
                                         typeck.node_args_opt(hir_id).map(|args| &args[1..]).unwrap_or_default()
@@ -443,7 +437,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                                     count: deref_count - required_refs,
                                     msg,
                                     stability,
-                                    for_field_access: if let ExprUseNode::FieldAccess(name) = use_cx.node
+                                    for_field_access: if let ExprUseNode::FieldAccess(name) = use_node
                                         && !use_cx.moved_before_use
                                     {
                                         Some(name.name)
@@ -453,7 +447,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                                 }),
                                 StateData {
                                     first_expr: expr,
-                                    adjusted_ty: use_cx.adjustments.last().map_or(expr_ty, |a| a.target),
+                                    adjusted_ty,
                                 },
                             ));
                         } else if stability.is_deref_stable()
@@ -465,12 +459,12 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                                 State::Borrow { mutability },
                                 StateData {
                                     first_expr: expr,
-                                    adjusted_ty: use_cx.adjustments.last().map_or(expr_ty, |a| a.target),
+                                    adjusted_ty,
                                 },
                             ));
                         }
                     },
-                    (None, _) | (_, RefOp::Method { .. }) => (),
+                    _ => {},
                 }
             },
             (
@@ -1013,7 +1007,7 @@ fn report<'tcx>(
                     let (precedence, calls_field) = match cx.tcx.parent_hir_node(data.first_expr.hir_id) {
                         Node::Expr(e) => match e.kind {
                             ExprKind::Call(callee, _) if callee.hir_id != data.first_expr.hir_id => (0, false),
-                            ExprKind::Call(..) => (PREC_POSTFIX, matches!(expr.kind, ExprKind::Field(..))),
+                            ExprKind::Call(..) => (PREC_UNAMBIGUOUS, matches!(expr.kind, ExprKind::Field(..))),
                             _ => (e.precedence().order(), false),
                         },
                         _ => (0, false),
@@ -1160,7 +1154,7 @@ impl<'tcx> Dereferencing<'tcx> {
                         },
                         Some(parent) if !parent.span.from_expansion() => {
                             // Double reference might be needed at this point.
-                            if parent.precedence().order() == PREC_POSTFIX {
+                            if parent.precedence().order() == PREC_UNAMBIGUOUS {
                                 // Parentheses would be needed here, don't lint.
                                 *outer_pat = None;
                             } else {
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index 3d875e7ac2d..3e210fd153b 100644
--- a/src/tools/clippy/clippy_lints/src/doc/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -6,10 +6,10 @@ use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::Visitable;
 use clippy_utils::{in_constant, is_entrypoint_fn, is_trait_impl_item, method_chain_args};
 use pulldown_cmark::Event::{
-    Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text,
+    Code, DisplayMath, End, FootnoteReference, HardBreak, Html, InlineHtml, InlineMath, Rule, SoftBreak, Start, TaskListMarker, Text,
 };
 use pulldown_cmark::Tag::{BlockQuote, CodeBlock, FootnoteDefinition, Heading, Item, Link, Paragraph};
-use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options};
+use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options, TagEnd};
 use rustc_ast::ast::Attribute;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::intravisit::{self, Visitor};
@@ -659,7 +659,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
 
     while let Some((event, range)) = events.next() {
         match event {
-            Html(tag) => {
+            Html(tag) | InlineHtml(tag) => {
                 if tag.starts_with("<code") {
                     code_level += 1;
                 } else if tag.starts_with("</code") {
@@ -670,11 +670,11 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                     blockquote_level -= 1;
                 }
             },
-            Start(BlockQuote) => {
+            Start(BlockQuote(_)) => {
                 blockquote_level += 1;
                 containers.push(Container::Blockquote);
             },
-            End(BlockQuote) => {
+            End(TagEnd::BlockQuote) => {
                 blockquote_level -= 1;
                 containers.pop();
             },
@@ -699,15 +699,15 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                     }
                 }
             },
-            End(CodeBlock(_)) => {
+            End(TagEnd::CodeBlock) => {
                 in_code = false;
                 is_rust = false;
                 ignore = false;
             },
-            Start(Link(_, url, _)) => in_link = Some(url),
-            End(Link(..)) => in_link = None,
-            Start(Heading(_, _, _) | Paragraph | Item) => {
-                if let Start(Heading(_, _, _)) = event {
+            Start(Link { dest_url, .. }) => in_link = Some(dest_url),
+            End(TagEnd::Link) => in_link = None,
+            Start(Heading { .. } | Paragraph | Item) => {
+                if let Start(Heading { .. }) = event {
                     in_heading = true;
                 }
                 if let Start(Item) = event {
@@ -720,11 +720,11 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                 ticks_unbalanced = false;
                 paragraph_range = range;
             },
-            End(Heading(_, _, _) | Paragraph | Item) => {
-                if let End(Heading(_, _, _)) = event {
+            End(TagEnd::Heading(_) | TagEnd::Paragraph | TagEnd::Item) => {
+                if let End(TagEnd::Heading(_)) = event {
                     in_heading = false;
                 }
-                if let End(Item) = event {
+                if let End(TagEnd::Item) = event {
                     containers.pop();
                 }
                 if ticks_unbalanced && let Some(span) = fragments.span(cx, paragraph_range.clone()) {
@@ -746,8 +746,8 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                 text_to_check = Vec::new();
             },
             Start(FootnoteDefinition(..)) => in_footnote_definition = true,
-            End(FootnoteDefinition(..)) => in_footnote_definition = false,
-            Start(_tag) | End(_tag) => (), // We don't care about other tags
+            End(TagEnd::FootnoteDefinition) => in_footnote_definition = false,
+            Start(_) | End(_) => (), // We don't care about other tags
             SoftBreak | HardBreak => {
                 if !containers.is_empty()
                     && let Some((next_event, next_range)) = events.peek()
@@ -765,7 +765,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                     );
                 }
             },
-            TaskListMarker(_) | Code(_) | Rule => (),
+            TaskListMarker(_) | Code(_) | Rule | InlineMath(..) | DisplayMath(..) => (),
             FootnoteReference(text) | Text(text) => {
                 paragraph_range.end = range.end;
                 ticks_unbalanced |= text.contains('`') && !in_code;
diff --git a/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs b/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs
index 745599b0e57..743ec5b9ea7 100644
--- a/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs
@@ -16,7 +16,7 @@ declare_clippy_lint! {
     /// and it may be desirable to do so consistently for style.
     ///
     /// However, removing the brackets also introduces a public constant named after the struct,
-    /// so this is not just a syntactic simplification but an an API change, and adding them back
+    /// so this is not just a syntactic simplification but an API change, and adding them back
     /// is a *breaking* API change.
     ///
     /// ### Example
@@ -44,7 +44,7 @@ declare_clippy_lint! {
     /// and it may be desirable to do so consistently for style.
     ///
     /// However, removing the brackets also introduces a public constant named after the variant,
-    /// so this is not just a syntactic simplification but an an API change, and adding them back
+    /// so this is not just a syntactic simplification but an API change, and adding them back
     /// is a *breaking* API change.
     ///
     /// ### Example
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 42ec2c00823..d2a34c75583 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -15,7 +15,7 @@ use rustc_middle::ty::{
 use rustc_session::declare_lint_pass;
 use rustc_span::symbol::sym;
 use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
+use rustc_trait_selection::error_reporting::traits::InferCtxtExt as _;
 
 declare_clippy_lint! {
     /// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs b/src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs
new file mode 100644
index 00000000000..bb74e345703
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs
@@ -0,0 +1,75 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use rustc_ast::ast::{Item, ItemKind, VisibilityKind};
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_session::declare_lint_pass;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of scoped visibility modifiers, like `pub(crate)`, on fields. These
+    /// make a field visible within a scope between public and private.
+    ///
+    /// ### Why restrict this?
+    /// Scoped visibility modifiers cause a field to be accessible within some scope between
+    /// public and private, potentially within an entire crate. This allows for fields to be
+    /// non-private while upholding internal invariants, but can be a code smell. Scoped visibility
+    /// requires checking a greater area, potentially an entire crate, to verify that an invariant
+    /// is upheld, and global analysis requires a lot of effort.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// pub mod public_module {
+    ///     struct MyStruct {
+    ///         pub(crate) first_field: bool,
+    ///         pub(super) second_field: bool
+    ///     }
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// pub mod public_module {
+    ///     struct MyStruct {
+    ///         first_field: bool,
+    ///         second_field: bool
+    ///     }
+    ///     impl MyStruct {
+    ///         pub(crate) fn get_first_field(&self) -> bool {
+    ///             self.first_field
+    ///         }
+    ///         pub(super) fn get_second_field(&self) -> bool {
+    ///             self.second_field
+    ///         }
+    ///     }
+    /// }
+    /// ```
+    #[clippy::version = "1.78.0"]
+    pub FIELD_SCOPED_VISIBILITY_MODIFIERS,
+    restriction,
+    "checks for usage of a scoped visibility modifier, like `pub(crate)`, on fields"
+}
+
+declare_lint_pass!(FieldScopedVisibilityModifiers => [FIELD_SCOPED_VISIBILITY_MODIFIERS]);
+
+impl EarlyLintPass for FieldScopedVisibilityModifiers {
+    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
+        let ItemKind::Struct(ref st, _) = item.kind else {
+            return;
+        };
+        for field in st.fields() {
+            let VisibilityKind::Restricted { path, .. } = &field.vis.kind else {
+                continue;
+            };
+            if !path.segments.is_empty() && path.segments[0].ident.name == rustc_span::symbol::kw::SelfLower {
+                // pub(self) is equivalent to not using pub at all, so we ignore it
+                continue;
+            }
+            span_lint_and_help(
+                cx,
+                FIELD_SCOPED_VISIBILITY_MODIFIERS,
+                field.vis.span,
+                "scoped visibility modifier on a field",
+                None,
+                "consider making the field private and adding a scoped visibility method for it",
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/float_literal.rs b/src/tools/clippy/clippy_lints/src/float_literal.rs
index 4d301daabe4..2261fcdbdab 100644
--- a/src/tools/clippy/clippy_lints/src/float_literal.rs
+++ b/src/tools/clippy/clippy_lints/src/float_literal.rs
@@ -141,18 +141,17 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
 #[must_use]
 fn max_digits(fty: FloatTy) -> u32 {
     match fty {
-        // FIXME(f16_f128): replace the magic numbers once `{f16,f128}::DIGITS` are available
-        FloatTy::F16 => 3,
+        FloatTy::F16 => f16::DIGITS,
         FloatTy::F32 => f32::DIGITS,
         FloatTy::F64 => f64::DIGITS,
-        FloatTy::F128 => 33,
+        FloatTy::F128 => f128::DIGITS,
     }
 }
 
 /// Counts the digits excluding leading zeros
 #[must_use]
 fn count_digits(s: &str) -> usize {
-    // Note that s does not contain the f32/64 suffix, and underscores have been stripped
+    // Note that s does not contain the `f{16,32,64,128}` suffix, and underscores have been stripped
     s.chars()
         .filter(|c| *c != '-' && *c != '.')
         .take_while(|c| *c != 'e' && *c != 'E')
diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs
index cb1d0de1edf..1fd8faf3ea8 100644
--- a/src/tools/clippy/clippy_lints/src/future_not_send.rs
+++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs
@@ -9,7 +9,7 @@ use rustc_middle::ty::{self, AliasTy, ClauseKind, PredicateKind};
 use rustc_session::declare_lint_pass;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{sym, Span};
-use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
+use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt;
 use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCtxt};
 
 declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
index ca830af3b2f..344a04e6e7e 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
@@ -14,7 +14,7 @@ use rustc_span::symbol::sym;
 use rustc_span::Span;
 
 use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
-use clippy_utils::source::{snippet, snippet_opt};
+use clippy_utils::source::{snippet, IntoSpan, SpanRangeExt};
 use clippy_utils::ty::is_type_diagnostic_item;
 
 declare_clippy_lint! {
@@ -59,10 +59,8 @@ declare_clippy_lint! {
 declare_lint_pass!(ImplicitHasher => [IMPLICIT_HASHER]);
 
 impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
-    #[expect(clippy::cast_possible_truncation, clippy::too_many_lines)]
+    #[expect(clippy::too_many_lines)]
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        use rustc_span::BytePos;
-
         fn suggestion(
             cx: &LateContext<'_>,
             diag: &mut Diag<'_, ()>,
@@ -123,10 +121,11 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
                     }
 
                     let generics_suggestion_span = impl_.generics.span.substitute_dummy({
-                        let pos = snippet_opt(cx, item.span.until(target.span()))
-                            .and_then(|snip| Some(item.span.lo() + BytePos(snip.find("impl")? as u32 + 4)));
-                        if let Some(pos) = pos {
-                            Span::new(pos, pos, item.span.ctxt(), item.span.parent())
+                        let range = (item.span.lo()..target.span().lo()).map_range(cx, |src, range| {
+                            Some(src.get(range.clone())?.find("impl")? + 4..range.end)
+                        });
+                        if let Some(range) = range {
+                            range.with_ctxt(item.span.ctxt())
                         } else {
                             return;
                         }
@@ -163,21 +162,16 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
                             continue;
                         }
                         let generics_suggestion_span = generics.span.substitute_dummy({
-                            let pos = snippet_opt(
-                                cx,
-                                Span::new(
-                                    item.span.lo(),
-                                    body.params[0].pat.span.lo(),
-                                    item.span.ctxt(),
-                                    item.span.parent(),
-                                ),
-                            )
-                            .and_then(|snip| {
-                                let i = snip.find("fn")?;
-                                Some(item.span.lo() + BytePos((i + snip[i..].find('(')?) as u32))
-                            })
-                            .expect("failed to create span for type parameters");
-                            Span::new(pos, pos, item.span.ctxt(), item.span.parent())
+                            let range = (item.span.lo()..body.params[0].pat.span.lo()).map_range(cx, |src, range| {
+                                let (pre, post) = src.get(range.clone())?.split_once("fn")?;
+                                let pos = post.find('(')? + pre.len() + 2;
+                                Some(pos..pos)
+                            });
+                            if let Some(range) = range {
+                                range.with_ctxt(item.span.ctxt())
+                            } else {
+                                return;
+                            }
                         });
 
                         let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target);
diff --git a/src/tools/clippy/clippy_lints/src/implicit_return.rs b/src/tools/clippy/clippy_lints/src/implicit_return.rs
index 2f543781c44..a102b434cfa 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_return.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_return.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::source::{snippet_with_applicability, snippet_with_context, walk_span_to_context};
 use clippy_utils::visitors::for_each_expr_without_closures;
-use clippy_utils::{get_async_fn_body, is_async_fn};
+use clippy_utils::{get_async_fn_body, is_async_fn, is_from_proc_macro};
 use core::ops::ControlFlow;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
@@ -245,6 +245,10 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitReturn {
         } else {
             body.value
         };
+
+        if is_from_proc_macro(cx, expr) {
+            return;
+        }
         lint_implicit_returns(cx, expr, expr.span.ctxt(), None);
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
index 170ecf896b4..67b48878ca5 100644
--- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
@@ -246,7 +246,7 @@ fn collect_supertrait_bounds<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds
                 && let [.., path] = poly_trait.trait_ref.path.segments
                 && poly_trait.bound_generic_params.is_empty()
                 && let Some(trait_def_id) = path.res.opt_def_id()
-                && let predicates = cx.tcx.super_predicates_of(trait_def_id).predicates
+                && let predicates = cx.tcx.explicit_super_predicates_of(trait_def_id).predicates
                 // If the trait has no supertrait, there is no need to collect anything from that bound
                 && !predicates.is_empty()
             {
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index c65581d5203..32fad0f02ce 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -1,10 +1,12 @@
 #![feature(array_windows)]
 #![feature(binary_heap_into_iter_sorted)]
 #![feature(box_patterns)]
+#![feature(f128)]
+#![feature(f16)]
 #![feature(if_let_guard)]
 #![feature(iter_intersperse)]
 #![feature(let_chains)]
-#![feature(lint_reasons)]
+#![cfg_attr(bootstrap, feature(lint_reasons))]
 #![feature(never_type)]
 #![feature(rustc_private)]
 #![feature(stmt_expr_attributes)]
@@ -71,7 +73,6 @@ mod renamed_lints;
 
 // begin lints modules, do not remove this comment, it’s used in `update_lints`
 mod absolute_paths;
-mod allow_attributes;
 mod almost_complete_range;
 mod approx_const;
 mod arc_with_non_send_sync;
@@ -136,6 +137,7 @@ mod exit;
 mod explicit_write;
 mod extra_unused_type_parameters;
 mod fallible_impl_from;
+mod field_scoped_visibility_modifiers;
 mod float_literal;
 mod floating_point_arithmetic;
 mod format;
@@ -697,7 +699,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(|_| Box::new(mut_reference::UnnecessaryMutPassed));
     store.register_late_pass(|_| Box::<significant_drop_tightening::SignificantDropTightening<'_>>::default());
     store.register_late_pass(|_| Box::new(len_zero::LenZero));
-    store.register_late_pass(|_| Box::new(attrs::Attributes));
+    store.register_late_pass(move |_| Box::new(attrs::Attributes::new(msrv())));
     store.register_late_pass(|_| Box::new(blocks_in_conditions::BlocksInConditions));
     store.register_late_pass(|_| Box::new(unicode::Unicode));
     store.register_late_pass(|_| Box::new(uninit_vec::UninitVec));
@@ -1063,7 +1065,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(|_| Box::new(needless_maybe_sized::NeedlessMaybeSized));
     store.register_late_pass(|_| Box::new(redundant_async_block::RedundantAsyncBlock));
     store.register_late_pass(|_| Box::new(let_with_type_underscore::UnderscoreTyped));
-    store.register_late_pass(|_| Box::new(allow_attributes::AllowAttribute));
     store.register_late_pass(move |_| Box::new(manual_main_separator_str::ManualMainSeparatorStr::new(msrv())));
     store.register_late_pass(|_| Box::new(unnecessary_struct_initialization::UnnecessaryStruct));
     store.register_late_pass(move |_| {
@@ -1168,7 +1169,8 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
             ..Default::default()
         })
     });
-    store.register_late_pass(|_| Box::new(string_patterns::StringPatterns));
+    store.register_late_pass(move |_| Box::new(string_patterns::StringPatterns::new(msrv())));
+    store.register_early_pass(|| Box::new(field_scoped_visibility_modifiers::FieldScopedVisibilityModifiers));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs
index 08682942153..64ea591993d 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs
@@ -356,10 +356,10 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for loops which have a range bound that is a mutable variable
+    /// Checks for loops with a range bound that is a mutable variable.
     ///
     /// ### Why is this bad?
-    /// One might think that modifying the mutable variable changes the loop bounds
+    /// One might think that modifying the mutable variable changes the loop bounds. It doesn't.
     ///
     /// ### Known problems
     /// False positive when mutation is followed by a `break`, but the `break` is not immediately
@@ -381,7 +381,7 @@ declare_clippy_lint! {
     /// let mut foo = 42;
     /// for i in 0..foo {
     ///     foo -= 1;
-    ///     println!("{}", i); // prints numbers from 0 to 42, not 0 to 21
+    ///     println!("{i}"); // prints numbers from 0 to 41, not 0 to 21
     /// }
     /// ```
     #[clippy::version = "pre 1.29.0"]
diff --git a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
index 72cf1d7a354..89eea0b4456 100644
--- a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
@@ -156,6 +156,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
 
 fn is_infinity(constant: &Constant<'_>) -> bool {
     match constant {
+        // FIXME(f16_f128): add f16 and f128 when constants are available
         Constant::F32(float) => *float == f32::INFINITY,
         Constant::F64(float) => *float == f64::INFINITY,
         _ => false,
@@ -164,6 +165,7 @@ fn is_infinity(constant: &Constant<'_>) -> bool {
 
 fn is_neg_infinity(constant: &Constant<'_>) -> bool {
     match constant {
+        // FIXME(f16_f128): add f16 and f128 when constants are available
         Constant::F32(float) => *float == f32::NEG_INFINITY,
         Constant::F64(float) => *float == f64::NEG_INFINITY,
         _ => false,
diff --git a/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs b/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs
index 17399fb2cc2..58b2ebebbf0 100644
--- a/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs
@@ -53,6 +53,7 @@ declare_lint_pass!(ManualUnwrapOrDefault => [MANUAL_UNWRAP_OR_DEFAULT]);
 
 fn get_some<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option<HirId> {
     if let PatKind::TupleStruct(QPath::Resolved(_, path), &[pat], _) = pat.kind
+        && let PatKind::Binding(_, 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.
@@ -60,13 +61,7 @@ fn get_some<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option<HirId> {
         && (cx.tcx.lang_items().get(LangItem::OptionSome) == Some(def_id)
         || cx.tcx.lang_items().get(LangItem::ResultOk) == Some(def_id))
     {
-        let mut bindings = Vec::new();
-        pat.each_binding(|_, id, _, _| bindings.push(id));
-        if let &[id] = bindings.as_slice() {
-            Some(id)
-        } else {
-            None
-        }
+        Some(pat_id)
     } else {
         None
     }
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 9edd6c95404..0940fc3219b 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
@@ -3,46 +3,78 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::usage::contains_return_break_continue_macro;
-use clippy_utils::{is_res_lang_ctor, path_to_local_id, sugg};
+use clippy_utils::{is_res_lang_ctor, path_to_local_id, peel_blocks, sugg};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::LangItem::{OptionNone, ResultErr};
-use rustc_hir::{Arm, Expr, PatKind};
+use rustc_hir::{Arm, Expr, Pat, PatKind};
 use rustc_lint::LateContext;
+use rustc_middle::ty::Ty;
 use rustc_span::sym;
 
 use super::MANUAL_UNWRAP_OR;
 
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, scrutinee: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) {
+pub(super) fn check_match<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+    scrutinee: &'tcx Expr<'_>,
+    arms: &'tcx [Arm<'_>],
+) {
     let ty = cx.typeck_results().expr_ty(scrutinee);
-    if let Some(ty_name) = if is_type_diagnostic_item(cx, ty, sym::Option) {
+    if let Some((or_arm, unwrap_arm)) = applicable_or_arm(cx, arms) {
+        check_and_lint(cx, expr, unwrap_arm.pat, scrutinee, unwrap_arm.body, or_arm.body, ty);
+    }
+}
+
+pub(super) fn check_if_let<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    let_pat: &'tcx Pat<'_>,
+    let_expr: &'tcx Expr<'_>,
+    then_expr: &'tcx Expr<'_>,
+    else_expr: &'tcx Expr<'_>,
+) {
+    let ty = cx.typeck_results().expr_ty(let_expr);
+    check_and_lint(cx, expr, let_pat, let_expr, then_expr, peel_blocks(else_expr), ty);
+}
+
+fn check_and_lint<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    let_pat: &'tcx Pat<'_>,
+    let_expr: &'tcx Expr<'_>,
+    then_expr: &'tcx Expr<'_>,
+    else_expr: &'tcx Expr<'_>,
+    ty: Ty<'tcx>,
+) {
+    if let PatKind::TupleStruct(ref qpath, [unwrap_pat], _) = let_pat.kind
+        && let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(qpath, let_pat.hir_id)
+        && let Some(variant_id) = cx.tcx.opt_parent(ctor_id)
+        && (cx.tcx.lang_items().option_some_variant() == Some(variant_id)
+            || cx.tcx.lang_items().result_ok_variant() == Some(variant_id))
+        && let PatKind::Binding(_, binding_hir_id, ..) = unwrap_pat.kind
+        && path_to_local_id(peel_blocks(then_expr), binding_hir_id)
+        && cx.typeck_results().expr_adjustments(then_expr).is_empty()
+        && let Some(ty_name) = find_type_name(cx, ty)
+        && let Some(or_body_snippet) = snippet_opt(cx, else_expr.span)
+        && let Some(indent) = indent_of(cx, expr.span)
+        && constant_simple(cx, cx.typeck_results(), else_expr).is_some()
+    {
+        lint(cx, expr, let_expr, ty_name, or_body_snippet, indent);
+    }
+}
+
+fn find_type_name<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&'static str> {
+    if is_type_diagnostic_item(cx, ty, sym::Option) {
         Some("Option")
     } else if is_type_diagnostic_item(cx, ty, sym::Result) {
         Some("Result")
     } else {
         None
-    } && let Some(or_arm) = applicable_or_arm(cx, arms)
-        && let Some(or_body_snippet) = snippet_opt(cx, or_arm.body.span)
-        && let Some(indent) = indent_of(cx, expr.span)
-        && constant_simple(cx, cx.typeck_results(), or_arm.body).is_some()
-    {
-        let reindented_or_body = reindent_multiline(or_body_snippet.into(), true, Some(indent));
-
-        let mut app = Applicability::MachineApplicable;
-        let suggestion = sugg::Sugg::hir_with_context(cx, scrutinee, expr.span.ctxt(), "..", &mut app).maybe_par();
-        span_lint_and_sugg(
-            cx,
-            MANUAL_UNWRAP_OR,
-            expr.span,
-            format!("this pattern reimplements `{ty_name}::unwrap_or`"),
-            "replace with",
-            format!("{suggestion}.unwrap_or({reindented_or_body})",),
-            app,
-        );
     }
 }
 
-fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<&'a Arm<'a>> {
+fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<(&'a Arm<'a>, &'a Arm<'a>)> {
     if arms.len() == 2
         && arms.iter().all(|arm| arm.guard.is_none())
         && let Some((idx, or_arm)) = arms.iter().enumerate().find(|(_, arm)| match arm.pat.kind {
@@ -54,18 +86,33 @@ fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<&'
             _ => false,
         })
         && let unwrap_arm = &arms[1 - idx]
-        && let PatKind::TupleStruct(ref qpath, [unwrap_pat], _) = unwrap_arm.pat.kind
-        && let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(qpath, unwrap_arm.pat.hir_id)
-        && let Some(variant_id) = cx.tcx.opt_parent(ctor_id)
-        && (cx.tcx.lang_items().option_some_variant() == Some(variant_id)
-            || cx.tcx.lang_items().result_ok_variant() == Some(variant_id))
-        && let PatKind::Binding(_, binding_hir_id, ..) = unwrap_pat.kind
-        && path_to_local_id(unwrap_arm.body, binding_hir_id)
-        && cx.typeck_results().expr_adjustments(unwrap_arm.body).is_empty()
         && !contains_return_break_continue_macro(or_arm.body)
     {
-        Some(or_arm)
+        Some((or_arm, unwrap_arm))
     } else {
         None
     }
 }
+
+fn lint<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &Expr<'tcx>,
+    scrutinee: &'tcx Expr<'_>,
+    ty_name: &str,
+    or_body_snippet: String,
+    indent: usize,
+) {
+    let reindented_or_body = reindent_multiline(or_body_snippet.into(), true, Some(indent));
+
+    let mut app = Applicability::MachineApplicable;
+    let suggestion = sugg::Sugg::hir_with_context(cx, scrutinee, expr.span.ctxt(), "..", &mut app).maybe_par();
+    span_lint_and_sugg(
+        cx,
+        MANUAL_UNWRAP_OR,
+        expr.span,
+        format!("this pattern reimplements `{ty_name}::unwrap_or`"),
+        "replace with",
+        format!("{suggestion}.unwrap_or({reindented_or_body})",),
+        app,
+    );
+}
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
index 183caab56c5..be80aebed6d 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
@@ -7,7 +7,7 @@ use clippy_utils::{
     can_move_expr_to_closure, is_else_clause, is_lint_allowed, is_res_lang_ctor, path_res, path_to_local_id,
     peel_blocks, peel_hir_expr_refs, peel_hir_expr_while, CaptureKind,
 };
-use rustc_ast::util::parser::PREC_POSTFIX;
+use rustc_ast::util::parser::PREC_UNAMBIGUOUS;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::LangItem::{OptionNone, OptionSome};
@@ -117,7 +117,7 @@ where
     // it's being passed by value.
     let scrutinee = peel_hir_expr_refs(scrutinee).0;
     let (scrutinee_str, _) = snippet_with_context(cx, scrutinee.span, expr_ctxt, "..", &mut app);
-    let scrutinee_str = if scrutinee.span.eq_ctxt(expr.span) && scrutinee.precedence().order() < PREC_POSTFIX {
+    let scrutinee_str = if scrutinee.span.eq_ctxt(expr.span) && scrutinee.precedence().order() < PREC_UNAMBIGUOUS {
         format!("({scrutinee_str})")
     } else {
         scrutinee_str.into()
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index 691ecd57535..bf7156cc53e 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -1069,7 +1069,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
                     redundant_guards::check(cx, arms, &self.msrv);
 
                     if !in_constant(cx, expr.hir_id) {
-                        manual_unwrap_or::check(cx, expr, ex, arms);
+                        manual_unwrap_or::check_match(cx, expr, ex, arms);
                         manual_map::check_match(cx, expr, ex, arms);
                         manual_filter::check_match(cx, ex, arms, expr);
                     }
@@ -1097,6 +1097,14 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
                         );
                     }
                     if !in_constant(cx, expr.hir_id) {
+                        manual_unwrap_or::check_if_let(
+                            cx,
+                            expr,
+                            if_let.let_pat,
+                            if_let.let_expr,
+                            if_let.if_then,
+                            else_expr,
+                        );
                         manual_map::check_if_let(cx, expr, if_let.let_pat, if_let.let_expr, if_let.if_then, else_expr);
                         manual_filter::check_if_let(
                             cx,
diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
index 69791414f72..99fdbcff890 100644
--- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::{expr_block, get_source_text, snippet};
+use clippy_utils::source::{expr_block, snippet, SpanRangeExt};
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, peel_mid_ty_refs};
 use clippy_utils::{is_lint_allowed, is_unit_expr, is_wild, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs};
 use core::cmp::max;
@@ -17,7 +17,7 @@ use super::{MATCH_BOOL, SINGLE_MATCH, SINGLE_MATCH_ELSE};
 /// span, e.g. a string literal `"//"`, but we know that this isn't the case for empty
 /// match arms.
 fn empty_arm_has_comment(cx: &LateContext<'_>, span: Span) -> bool {
-    if let Some(ff) = get_source_text(cx, span)
+    if let Some(ff) = span.get_source_text(cx)
         && let Some(text) = ff.as_str()
     {
         text.as_bytes().windows(2).any(|w| w == b"//" || w == b"/*")
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs
new file mode 100644
index 00000000000..e3ce64c246a
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs
@@ -0,0 +1,238 @@
+use clippy_config::msrvs::{self, Msrv};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::{IntoSpan, SpanRangeExt};
+use clippy_utils::ty::get_field_by_name;
+use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures};
+use clippy_utils::{expr_use_ctxt, is_diag_item_method, is_diag_trait_item, path_to_local_id, ExprUseNode};
+use core::ops::ControlFlow;
+use rustc_errors::Applicability;
+use rustc_hir::{BindingMode, BorrowKind, ByRef, ClosureKind, Expr, ExprKind, Mutability, Node, PatKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
+use rustc_span::{sym, Span, Symbol, DUMMY_SP};
+
+use super::MANUAL_INSPECT;
+
+#[expect(clippy::too_many_lines)]
+pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: &str, name_span: Span, msrv: &Msrv) {
+    if let ExprKind::Closure(c) = arg.kind
+        && matches!(c.kind, ClosureKind::Closure)
+        && let typeck = cx.typeck_results()
+        && let Some(fn_id) = typeck.type_dependent_def_id(expr.hir_id)
+        && (is_diag_trait_item(cx, fn_id, sym::Iterator)
+            || (msrv.meets(msrvs::OPTION_RESULT_INSPECT)
+                && (is_diag_item_method(cx, fn_id, sym::Option) || is_diag_item_method(cx, fn_id, sym::Result))))
+        && let body = cx.tcx.hir().body(c.body)
+        && let [param] = body.params
+        && let PatKind::Binding(BindingMode(ByRef::No, Mutability::Not), arg_id, _, None) = param.pat.kind
+        && let arg_ty = typeck.node_type(arg_id)
+        && let ExprKind::Block(block, _) = body.value.kind
+        && let Some(final_expr) = block.expr
+        && !block.stmts.is_empty()
+        && path_to_local_id(final_expr, arg_id)
+        && typeck.expr_adjustments(final_expr).is_empty()
+    {
+        let mut requires_copy = false;
+        let mut requires_deref = false;
+
+        // The number of unprocessed return expressions.
+        let mut ret_count = 0u32;
+
+        // The uses for which processing is delayed until after the visitor.
+        let mut delayed = vec![];
+
+        let ctxt = arg.span.ctxt();
+        let can_lint = for_each_expr_without_closures(block.stmts, |e| {
+            if let ExprKind::Closure(c) = e.kind {
+                // Nested closures don't need to treat returns specially.
+                let _: Option<!> = for_each_expr(cx, cx.tcx.hir().body(c.body).value, |e| {
+                    if path_to_local_id(e, arg_id) {
+                        let (kind, same_ctxt) = check_use(cx, e);
+                        match (kind, same_ctxt && e.span.ctxt() == ctxt) {
+                            (_, false) | (UseKind::Deref | UseKind::Return(..), true) => {
+                                requires_copy = true;
+                                requires_deref = true;
+                            },
+                            (UseKind::AutoBorrowed, true) => {},
+                            (UseKind::WillAutoDeref, true) => {
+                                requires_copy = true;
+                            },
+                            (kind, true) => delayed.push(kind),
+                        }
+                    }
+                    ControlFlow::Continue(())
+                });
+            } else if matches!(e.kind, ExprKind::Ret(_)) {
+                ret_count += 1;
+            } else if path_to_local_id(e, arg_id) {
+                let (kind, same_ctxt) = check_use(cx, e);
+                match (kind, same_ctxt && e.span.ctxt() == ctxt) {
+                    (UseKind::Return(..), false) => {
+                        return ControlFlow::Break(());
+                    },
+                    (_, false) | (UseKind::Deref, true) => {
+                        requires_copy = true;
+                        requires_deref = true;
+                    },
+                    (UseKind::AutoBorrowed, true) => {},
+                    (UseKind::WillAutoDeref, true) => {
+                        requires_copy = true;
+                    },
+                    (kind @ UseKind::Return(_), true) => {
+                        ret_count -= 1;
+                        delayed.push(kind);
+                    },
+                    (kind, true) => delayed.push(kind),
+                }
+            }
+            ControlFlow::Continue(())
+        })
+        .is_none();
+
+        if ret_count != 0 {
+            // A return expression that didn't return the original value was found.
+            return;
+        }
+
+        let mut edits = Vec::with_capacity(delayed.len() + 3);
+        let mut addr_of_edits = Vec::with_capacity(delayed.len());
+        for x in delayed {
+            match x {
+                UseKind::Return(s) => edits.push((s.with_leading_whitespace(cx).with_ctxt(s.ctxt()), String::new())),
+                UseKind::Borrowed(s) => {
+                    #[expect(clippy::range_plus_one)]
+                    let range = s.map_range(cx, |src, range| {
+                        let src = src.get(range.clone())?;
+                        let trimmed = src.trim_start_matches([' ', '\t', '\n', '\r', '(']);
+                        trimmed.starts_with('&').then(|| {
+                            let pos = range.start + src.len() - trimmed.len();
+                            pos..pos + 1
+                        })
+                    });
+                    if let Some(range) = range {
+                        addr_of_edits.push((range.with_ctxt(s.ctxt()), String::new()));
+                    } else {
+                        requires_copy = true;
+                        requires_deref = true;
+                    }
+                },
+                UseKind::FieldAccess(name, e) => {
+                    let Some(mut ty) = get_field_by_name(cx.tcx, arg_ty.peel_refs(), name) else {
+                        requires_copy = true;
+                        continue;
+                    };
+                    let mut prev_expr = e;
+
+                    for (_, parent) in cx.tcx.hir().parent_iter(e.hir_id) {
+                        if let Node::Expr(e) = parent {
+                            match e.kind {
+                                ExprKind::Field(_, name)
+                                    if let Some(fty) = get_field_by_name(cx.tcx, ty.peel_refs(), name.name) =>
+                                {
+                                    ty = fty;
+                                    prev_expr = e;
+                                    continue;
+                                },
+                                ExprKind::AddrOf(BorrowKind::Ref, ..) => break,
+                                _ if matches!(
+                                    typeck.expr_adjustments(prev_expr).first(),
+                                    Some(Adjustment {
+                                        kind: Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Not))
+                                            | Adjust::Deref(_),
+                                        ..
+                                    })
+                                ) =>
+                                {
+                                    break;
+                                },
+                                _ => {},
+                            }
+                        }
+                        requires_copy |= !ty.is_copy_modulo_regions(cx.tcx, cx.param_env);
+                        break;
+                    }
+                },
+                // Already processed uses.
+                UseKind::AutoBorrowed | UseKind::WillAutoDeref | UseKind::Deref => {},
+            }
+        }
+
+        if can_lint
+            && (!requires_copy || arg_ty.is_copy_modulo_regions(cx.tcx, cx.param_env))
+            // This case could be handled, but a fair bit of care would need to be taken.
+            && (!requires_deref || arg_ty.is_freeze(cx.tcx, cx.param_env))
+        {
+            if requires_deref {
+                edits.push((param.span.shrink_to_lo(), "&".into()));
+            } else {
+                edits.extend(addr_of_edits);
+            }
+            edits.push((
+                name_span,
+                String::from(match name {
+                    "map" => "inspect",
+                    "map_err" => "inspect_err",
+                    _ => return,
+                }),
+            ));
+            edits.push((
+                final_expr
+                    .span
+                    .with_leading_whitespace(cx)
+                    .with_ctxt(final_expr.span.ctxt()),
+                String::new(),
+            ));
+            let app = if edits.iter().any(|(s, _)| s.from_expansion()) {
+                Applicability::MaybeIncorrect
+            } else {
+                Applicability::MachineApplicable
+            };
+            span_lint_and_then(cx, MANUAL_INSPECT, name_span, "", |diag| {
+                diag.multipart_suggestion("try", edits, app);
+            });
+        }
+    }
+}
+
+enum UseKind<'tcx> {
+    AutoBorrowed,
+    WillAutoDeref,
+    Deref,
+    Return(Span),
+    Borrowed(Span),
+    FieldAccess(Symbol, &'tcx Expr<'tcx>),
+}
+
+/// Checks how the value is used, and whether it was used in the same `SyntaxContext`.
+fn check_use<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (UseKind<'tcx>, bool) {
+    let use_cx = expr_use_ctxt(cx, e);
+    if use_cx
+        .adjustments
+        .first()
+        .is_some_and(|a| matches!(a.kind, Adjust::Deref(_)))
+    {
+        return (UseKind::AutoBorrowed, use_cx.same_ctxt);
+    }
+    let res = match use_cx.use_node(cx) {
+        ExprUseNode::Return(_) => {
+            if let ExprKind::Ret(Some(e)) = use_cx.node.expect_expr().kind {
+                UseKind::Return(e.span)
+            } else {
+                return (UseKind::Return(DUMMY_SP), false);
+            }
+        },
+        ExprUseNode::FieldAccess(name) => UseKind::FieldAccess(name.name, use_cx.node.expect_expr()),
+        ExprUseNode::Callee | ExprUseNode::MethodArg(_, _, 0)
+            if use_cx
+                .adjustments
+                .first()
+                .is_some_and(|a| matches!(a.kind, Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Not)))) =>
+        {
+            UseKind::AutoBorrowed
+        },
+        ExprUseNode::Callee | ExprUseNode::MethodArg(_, _, 0) => UseKind::WillAutoDeref,
+        ExprUseNode::AddrOf(BorrowKind::Ref, _) => UseKind::Borrowed(use_cx.node.expect_expr().span),
+        _ => UseKind::Deref,
+    };
+    (res, use_cx.same_ctxt)
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 6200716afbe..1408f454820 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -53,6 +53,7 @@ mod iter_with_drain;
 mod iterator_step_by_zero;
 mod join_absolute_paths;
 mod manual_c_str_literals;
+mod manual_inspect;
 mod manual_is_variant_and;
 mod manual_next_back;
 mod manual_ok_or;
@@ -116,6 +117,7 @@ mod unnecessary_iter_cloned;
 mod unnecessary_join;
 mod unnecessary_lazy_eval;
 mod unnecessary_literal_unwrap;
+mod unnecessary_min_or_max;
 mod unnecessary_result_map_or_else;
 mod unnecessary_sort_by;
 mod unnecessary_to_owned;
@@ -3946,6 +3948,31 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
+    /// Checks for unnecessary calls to `min()` or `max()` in the following cases
+    /// - Either both side is constant
+    /// - One side is clearly larger than the other, like i32::MIN and an i32 variable
+    ///
+    /// ### Why is this bad?
+    ///
+    /// In the aformentioned cases it is not necessary to call `min()` or `max()`
+    /// to compare values, it may even cause confusion.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// let _ = 0.min(7_u32);
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// let _ = 0;
+    /// ```
+    #[clippy::version = "1.78.0"]
+    pub UNNECESSARY_MIN_OR_MAX,
+    complexity,
+    "using 'min()/max()' when there is no need for it"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
     /// Checks for usage of `.map_or_else()` "map closure" for `Result` type.
     ///
     /// ### Why is this bad?
@@ -4079,6 +4106,27 @@ declare_clippy_lint! {
     "is_ascii() called on a char iterator"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for uses of `map` which return the original item.
+    ///
+    /// ### Why is this bad?
+    /// `inspect` is both clearer in intent and shorter.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// let x = Some(0).map(|x| { println!("{x}"); x });
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// let x = Some(0).inspect(|x| println!("{x}"));
+    /// ```
+    #[clippy::version = "1.78.0"]
+    pub MANUAL_INSPECT,
+    complexity,
+    "use of `map` returning the original item"
+}
+
 pub struct Methods {
     avoid_breaking_exported_api: bool,
     msrv: Msrv,
@@ -4244,6 +4292,8 @@ impl_lint_pass!(Methods => [
     MANUAL_C_STR_LITERALS,
     UNNECESSARY_GET_THEN_CHECK,
     NEEDLESS_CHARACTER_ITERATION,
+    MANUAL_INSPECT,
+    UNNECESSARY_MIN_OR_MAX,
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -4543,6 +4593,9 @@ impl Methods {
                     Some(("bytes", recv2, [], _, _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
                     _ => {},
                 },
+                ("min" | "max", [arg]) => {
+                    unnecessary_min_or_max::check(cx, expr, name, recv, arg);
+                },
                 ("drain", ..) => {
                     if let Node::Stmt(Stmt { hir_id: _, kind, .. }) = cx.tcx.parent_hir_node(expr.hir_id)
                         && matches!(kind, StmtKind::Semi(_))
@@ -4747,6 +4800,7 @@ impl Methods {
                         }
                     }
                     map_identity::check(cx, expr, recv, m_arg, name, span);
+                    manual_inspect::check(cx, expr, m_arg, name, span, &self.msrv);
                 },
                 ("map_or", [def, map]) => {
                     option_map_or_none::check(cx, expr, recv, def, map);
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 f26f164fa54..46b457daf70 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -206,7 +206,7 @@ fn iterates_same_ty<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'tcx>, collect_ty:
         && let Some(into_iter_item_proj) = make_projection(cx.tcx, into_iter_trait, sym::Item, [collect_ty])
         && let Ok(into_iter_item_ty) = cx.tcx.try_normalize_erasing_regions(
             cx.param_env,
-            Ty::new_projection(cx.tcx, into_iter_item_proj.def_id, into_iter_item_proj.args),
+            Ty::new_projection_from_args(cx.tcx, into_iter_item_proj.def_id, into_iter_item_proj.args),
         )
     {
         iter_item_ty == into_iter_item_ty
@@ -235,7 +235,7 @@ fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) -
             iter_trait,
         )
         && let args = cx.tcx.mk_args(&[GenericArg::from(typeck.expr_ty_adjusted(iter_expr))])
-        && let proj_ty = Ty::new_projection(cx.tcx, iter_item.def_id, args)
+        && let proj_ty = Ty::new_projection_from_args(cx.tcx, iter_item.def_id, args)
         && let Ok(item_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, proj_ty)
     {
         item_ty == EarlyBinder::bind(search_ty).instantiate(cx.tcx, cx.typeck_results().node_args(call_id))
diff --git a/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs b/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs
index 6f9b38fcf83..b62ecef0069 100644
--- a/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs
@@ -24,7 +24,7 @@ fn is_subtrait_of_any(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
                 cx.tcx.is_diagnostic_item(sym::Any, tr.def_id)
                     || cx
                         .tcx
-                        .super_predicates_of(tr.def_id)
+                        .explicit_super_predicates_of(tr.def_id)
                         .predicates
                         .iter()
                         .any(|(clause, _)| {
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs
new file mode 100644
index 00000000000..78851d4122f
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs
@@ -0,0 +1,90 @@
+use std::cmp::Ordering;
+
+use super::UNNECESSARY_MIN_OR_MAX;
+use clippy_utils::diagnostics::span_lint_and_sugg;
+
+use clippy_utils::consts::{constant, constant_with_source, Constant, ConstantSource, FullInt};
+use clippy_utils::source::snippet;
+
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_middle::ty;
+use rustc_span::Span;
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    name: &str,
+    recv: &'tcx Expr<'_>,
+    arg: &'tcx Expr<'_>,
+) {
+    let typeck_results = cx.typeck_results();
+    if let Some((left, ConstantSource::Local | ConstantSource::CoreConstant)) =
+        constant_with_source(cx, typeck_results, recv)
+        && let Some((right, ConstantSource::Local | ConstantSource::CoreConstant)) =
+            constant_with_source(cx, typeck_results, arg)
+    {
+        let Some(ord) = Constant::partial_cmp(cx.tcx, typeck_results.expr_ty(recv), &left, &right) else {
+            return;
+        };
+
+        lint(cx, expr, name, recv.span, arg.span, ord);
+    } else if let Some(extrema) = detect_extrema(cx, recv) {
+        let ord = match extrema {
+            Extrema::Minimum => Ordering::Less,
+            Extrema::Maximum => Ordering::Greater,
+        };
+        lint(cx, expr, name, recv.span, arg.span, ord);
+    } else if let Some(extrema) = detect_extrema(cx, arg) {
+        let ord = match extrema {
+            Extrema::Minimum => Ordering::Greater,
+            Extrema::Maximum => Ordering::Less,
+        };
+        lint(cx, expr, name, recv.span, arg.span, ord);
+    }
+}
+
+fn lint(cx: &LateContext<'_>, expr: &Expr<'_>, name: &str, lhs: Span, rhs: Span, order: Ordering) {
+    let cmp_str = if order.is_ge() { "smaller" } else { "greater" };
+
+    let suggested_value = if (name == "min" && order.is_ge()) || (name == "max" && order.is_le()) {
+        snippet(cx, rhs, "..")
+    } else {
+        snippet(cx, lhs, "..")
+    };
+
+    span_lint_and_sugg(
+        cx,
+        UNNECESSARY_MIN_OR_MAX,
+        expr.span,
+        format!(
+            "`{}` is never {} than `{}` and has therefore no effect",
+            snippet(cx, lhs, ".."),
+            cmp_str,
+            snippet(cx, rhs, "..")
+        ),
+        "try",
+        suggested_value.to_string(),
+        Applicability::MachineApplicable,
+    );
+}
+
+#[derive(Debug)]
+enum Extrema {
+    Minimum,
+    Maximum,
+}
+fn detect_extrema<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<Extrema> {
+    let ty = cx.typeck_results().expr_ty(expr);
+
+    let cv = constant(cx, cx.typeck_results(), expr)?;
+
+    match (cv.int_value(cx, ty)?, ty.kind()) {
+        (FullInt::S(i), &ty::Int(ity)) if i == i128::MIN >> (128 - ity.bit_width()?) => Some(Extrema::Minimum),
+        (FullInt::S(i), &ty::Int(ity)) if i == i128::MAX >> (128 - ity.bit_width()?) => Some(Extrema::Maximum),
+        (FullInt::U(i), &ty::Uint(uty)) if i == u128::MAX >> (128 - uty.bit_width()?) => Some(Extrema::Maximum),
+        (FullInt::U(0), &ty::Uint(_)) => Some(Extrema::Minimum),
+        _ => 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 4592324809f..bb0d714a31f 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
@@ -1,11 +1,11 @@
 use clippy_config::msrvs::{self, Msrv};
-use clippy_utils::diagnostics::span_lint;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::qualify_min_const_fn::is_min_const_fn;
 use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, trait_ref_of_method};
-use rustc_hir as hir;
+use rustc_errors::Applicability;
 use rustc_hir::def_id::CRATE_DEF_ID;
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Body, Constness, FnDecl, GenericParamKind};
+use rustc_hir::{self as hir, Body, Constness, FnDecl, GenericParamKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
@@ -120,7 +120,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
                 }
             },
             FnKind::Method(_, sig, ..) => {
-                if trait_ref_of_method(cx, def_id).is_some() || already_const(sig.header) {
+                if already_const(sig.header) || trait_ref_of_method(cx, def_id).is_some() {
                     return;
                 }
             },
@@ -147,10 +147,22 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
 
         let mir = cx.tcx.optimized_mir(def_id);
 
-        if let Ok(()) = is_min_const_fn(cx.tcx, mir, &self.msrv) {
-            span_lint(cx, MISSING_CONST_FOR_FN, span, "this could be a `const fn`");
+        if let Ok(()) = is_min_const_fn(cx.tcx, mir, &self.msrv)
+            && let hir::Node::Item(hir::Item { vis_span, .. }) | hir::Node::ImplItem(hir::ImplItem { vis_span, .. }) =
+                cx.tcx.hir_node_by_def_id(def_id)
+        {
+            let suggestion = if vis_span.is_empty() { "const " } else { " const" };
+            span_lint_and_then(cx, MISSING_CONST_FOR_FN, span, "this could be a `const fn`", |diag| {
+                diag.span_suggestion_verbose(
+                    vis_span.shrink_to_hi(),
+                    "make the function `const`",
+                    suggestion,
+                    Applicability::MachineApplicable,
+                );
+            });
         }
     }
+
     extract_msrv_attr!(LateContext);
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index ca344dc5c81..250fd5cbd48 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -8,7 +8,7 @@
 use clippy_utils::attrs::is_doc_hidden;
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::is_from_proc_macro;
-use clippy_utils::source::snippet_opt;
+use clippy_utils::source::SpanRangeExt;
 use rustc_ast::ast::{self, MetaItem, MetaItemKind};
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
@@ -266,8 +266,5 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
 }
 
 fn span_to_snippet_contains_docs(cx: &LateContext<'_>, search_span: Span) -> bool {
-    let Some(snippet) = snippet_opt(cx, search_span) else {
-        return false;
-    };
-    snippet.lines().rev().any(|line| line.trim().starts_with("///"))
+    search_span.check_source_text(cx, |src| src.lines().rev().any(|line| line.trim().starts_with("///")))
 }
diff --git a/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs b/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs
index d608f3bf7b4..d276e29bace 100644
--- a/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs
+++ b/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs
@@ -6,7 +6,7 @@ use rustc_session::declare_lint_pass;
 use rustc_span::Span;
 
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::source::snippet_opt;
+use clippy_utils::source::SpanRangeExt;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -54,8 +54,10 @@ impl EarlyLintPass for MultipleBoundLocations {
                 match clause {
                     WherePredicate::BoundPredicate(pred) => {
                         if (!pred.bound_generic_params.is_empty() || !pred.bounds.is_empty())
-                            && let Some(name) = snippet_opt(cx, pred.bounded_ty.span)
-                            && let Some(bound_span) = generic_params_with_bounds.get(name.as_str())
+                            && let Some(Some(bound_span)) = pred
+                                .bounded_ty
+                                .span
+                                .with_source_text(cx, |src| generic_params_with_bounds.get(src))
                         {
                             emit_lint(cx, *bound_span, pred.bounded_ty.span);
                         }
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
index 4f99eaa40c2..064ce59c234 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
@@ -80,11 +80,13 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if matches!(expr.kind, ExprKind::AddrOf(..))
             && !expr.span.from_expansion()
-            && let Some(use_cx) = expr_use_ctxt(cx, expr)
+            && let use_cx = expr_use_ctxt(cx, expr)
+            && use_cx.same_ctxt
             && !use_cx.is_ty_unified
-            && let Some(DefinedTy::Mir(ty)) = use_cx.node.defined_ty(cx)
+            && let use_node = use_cx.use_node(cx)
+            && let Some(DefinedTy::Mir(ty)) = use_node.defined_ty(cx)
             && let ty::Param(ty) = *ty.value.skip_binder().kind()
-            && let Some((hir_id, fn_id, i)) = match use_cx.node {
+            && let Some((hir_id, fn_id, i)) = match use_node {
                 ExprUseNode::MethodArg(_, _, 0) => None,
                 ExprUseNode::MethodArg(hir_id, None, i) => cx
                     .typeck_results()
@@ -267,7 +269,7 @@ fn needless_borrow_count<'tcx>(
                 return false;
             }
 
-            let predicate = EarlyBinder::bind(predicate).instantiate(cx.tcx, &args_with_referent_ty);
+            let predicate = EarlyBinder::bind(predicate).instantiate(cx.tcx, &args_with_referent_ty[..]);
             let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate);
             let infcx = cx.tcx.infer_ctxt().build();
             infcx.predicate_must_hold_modulo_regions(&obligation)
diff --git a/src/tools/clippy/clippy_lints/src/needless_else.rs b/src/tools/clippy/clippy_lints/src/needless_else.rs
index b6aad69d166..f8bb72a16db 100644
--- a/src/tools/clippy/clippy_lints/src/needless_else.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_else.rs
@@ -1,8 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::{snippet_opt, trim_span};
+use clippy_utils::source::{IntoSpan, SpanRangeExt};
 use rustc_ast::ast::{Expr, ExprKind};
 use rustc_errors::Applicability;
-use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
@@ -41,16 +41,16 @@ impl EarlyLintPass for NeedlessElse {
             && !expr.span.from_expansion()
             && !else_clause.span.from_expansion()
             && block.stmts.is_empty()
-            && let Some(trimmed) = expr.span.trim_start(then_block.span)
-            && let span = trim_span(cx.sess().source_map(), trimmed)
-            && let Some(else_snippet) = snippet_opt(cx, span)
-            // Ignore else blocks that contain comments or #[cfg]s
-            && !else_snippet.contains(['/', '#'])
+            && let range = (then_block.span.hi()..expr.span.hi()).trim_start(cx)
+            && range.clone().check_source_text(cx, |src| {
+                // Ignore else blocks that contain comments or #[cfg]s
+                !src.contains(['/', '#'])
+            })
         {
             span_lint_and_sugg(
                 cx,
                 NEEDLESS_ELSE,
-                span,
+                range.with_ctxt(expr.span.ctxt()),
                 "this `else` branch is empty",
                 "you can remove it",
                 String::new(),
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 630018238f4..143acc2b1cb 100644
--- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
@@ -25,14 +25,14 @@ declare_clippy_lint! {
     /// ```no_run
     /// let v = vec![0, 1, 2];
     /// v.iter().for_each(|elem| {
-    ///     println!("{}", elem);
+    ///     println!("{elem}");
     /// })
     /// ```
     /// Use instead:
     /// ```no_run
     /// let v = vec![0, 1, 2];
-    /// for elem in v.iter() {
-    ///     println!("{}", elem);
+    /// for elem in &v {
+    ///     println!("{elem}");
     /// }
     /// ```
     ///
diff --git a/src/tools/clippy/clippy_lints/src/needless_if.rs b/src/tools/clippy/clippy_lints/src/needless_if.rs
index 51bee4b51f6..1d6233d432a 100644
--- a/src/tools/clippy/clippy_lints/src/needless_if.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_if.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::higher::If;
 use clippy_utils::is_from_proc_macro;
-use clippy_utils::source::snippet_opt;
+use clippy_utils::source::{snippet_opt, SpanRangeExt};
 use rustc_errors::Applicability;
 use rustc_hir::{ExprKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -39,18 +39,24 @@ declare_lint_pass!(NeedlessIf => [NEEDLESS_IF]);
 impl LateLintPass<'_> for NeedlessIf {
     fn check_stmt<'tcx>(&mut self, cx: &LateContext<'tcx>, stmt: &Stmt<'tcx>) {
         if let StmtKind::Expr(expr) = stmt.kind
-            && let Some(If {cond, then, r#else: None }) = If::hir(expr)
+            && let Some(If {
+                cond,
+                then,
+                r#else: None,
+            }) = If::hir(expr)
             && let ExprKind::Block(block, ..) = then.kind
             && block.stmts.is_empty()
             && block.expr.is_none()
             && !in_external_macro(cx.sess(), expr.span)
-            && let Some(then_snippet) = snippet_opt(cx, then.span)
-            // Ignore
-            // - empty macro expansions
-            // - empty reptitions in macro expansions
-            // - comments
-            // - #[cfg]'d out code
-            && then_snippet.chars().all(|ch| matches!(ch, '{' | '}') || ch.is_ascii_whitespace())
+            && then.span.check_source_text(cx, |src| {
+                // Ignore
+                // - empty macro expansions
+                // - empty reptitions in macro expansions
+                // - comments
+                // - #[cfg]'d out code
+                src.bytes()
+                    .all(|ch| matches!(ch, b'{' | b'}') || ch.is_ascii_whitespace())
+            })
             && let Some(cond_snippet) = snippet_opt(cx, cond.span)
             && !is_from_proc_macro(cx, expr)
         {
diff --git a/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs b/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs
index 4922c87b206..a1d8ec3b32e 100644
--- a/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs
@@ -91,7 +91,7 @@ fn path_to_sized_bound(cx: &LateContext<'_>, trait_bound: &PolyTraitRef<'_>) ->
             return true;
         }
 
-        for &(predicate, _) in cx.tcx.super_predicates_of(trait_def_id).predicates {
+        for &(predicate, _) in cx.tcx.explicit_super_predicates_of(trait_def_id).predicates {
             if let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder()
                 && trait_predicate.polarity == PredicatePolarity::Positive
                 && !path.contains(&trait_predicate.def_id())
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 5cb8e7bfab2..09225ac3246 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -258,7 +258,7 @@ impl<'tcx> NonCopyConst<'tcx> {
                 // e.g. implementing `has_frozen_variant` described above, and not running this function
                 // when the type doesn't have any frozen variants would be the 'correct' way for the 2nd
                 // case (that actually removes another suboptimal behavior (I won't say 'false positive') where,
-                // similar to 2., but with the a frozen variant) (e.g. borrowing
+                // similar to 2., but with a frozen variant) (e.g. borrowing
                 // `borrow_interior_mutable_const::enums::AssocConsts::TO_BE_FROZEN_VARIANT`).
                 // I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none).
                 matches!(err, ErrorHandled::TooGeneric(..))
@@ -293,7 +293,7 @@ impl<'tcx> NonCopyConst<'tcx> {
         ct: ty::UnevaluatedConst<'tcx>,
         span: Span,
     ) -> EvalToValTreeResult<'tcx> {
-        match ty::Instance::resolve(tcx, param_env, ct.def, ct.args) {
+        match ty::Instance::try_resolve(tcx, param_env, ct.def, ct.args) {
             Ok(Some(instance)) => {
                 let cid = GlobalId {
                     instance,
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 2701d6bdca3..b915df52762 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,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::{snippet_opt, snippet_with_applicability};
+use clippy_utils::source::{snippet_with_applicability, SpanRangeExt};
 use clippy_utils::{match_def_path, paths};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
@@ -53,8 +53,9 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
                             && cx.tcx.is_diagnostic_item(sym::FsPermissions, adt.did())))
                     && let ExprKind::Lit(_) = param.kind
                     && param.span.eq_ctxt(expr.span)
-                    && let Some(snip) = snippet_opt(cx, param.span)
-                    && !(snip.starts_with("0o") || snip.starts_with("0b"))
+                    && param
+                        .span
+                        .check_source_text(cx, |src| !matches!(src.as_bytes(), [b'0', b'o' | b'b', ..]))
                 {
                     show_error(cx, param);
                 }
@@ -65,8 +66,9 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
                     && match_def_path(cx, def_id, &paths::PERMISSIONS_FROM_MODE)
                     && let ExprKind::Lit(_) = param.kind
                     && param.span.eq_ctxt(expr.span)
-                    && let Some(snip) = snippet_opt(cx, param.span)
-                    && !(snip.starts_with("0o") || snip.starts_with("0b"))
+                    && param
+                        .span
+                        .check_source_text(cx, |src| !matches!(src.as_bytes(), [b'0', b'o' | b'b', ..]))
                 {
                     show_error(cx, param);
                 }
diff --git a/src/tools/clippy/clippy_lints/src/octal_escapes.rs b/src/tools/clippy/clippy_lints/src/octal_escapes.rs
index 2fc039ae886..2eae9b23746 100644
--- a/src/tools/clippy/clippy_lints/src/octal_escapes.rs
+++ b/src/tools/clippy/clippy_lints/src/octal_escapes.rs
@@ -1,12 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use rustc_ast::ast::{Expr, ExprKind};
-use rustc_ast::token::{Lit, LitKind};
+use clippy_utils::source::SpanRangeExt;
+use rustc_ast::token::LitKind;
+use rustc_ast::{Expr, ExprKind};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
-use rustc_span::Span;
-use std::fmt::Write;
+use rustc_span::{BytePos, Pos, SpanData};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -52,104 +52,66 @@ declare_lint_pass!(OctalEscapes => [OCTAL_ESCAPES]);
 
 impl EarlyLintPass for OctalEscapes {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
-        if in_external_macro(cx.sess(), expr.span) {
-            return;
-        }
-
-        if let ExprKind::Lit(token_lit) = &expr.kind {
-            if matches!(token_lit.kind, LitKind::Str) {
-                check_lit(cx, token_lit, expr.span, true);
-            } else if matches!(token_lit.kind, LitKind::ByteStr) {
-                check_lit(cx, token_lit, expr.span, false);
-            }
-        }
-    }
-}
-
-fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) {
-    let contents = lit.symbol.as_str();
-    let mut iter = contents.char_indices().peekable();
-    let mut found = vec![];
+        if let ExprKind::Lit(lit) = &expr.kind
+            // The number of bytes from the start of the token to the start of literal's text.
+            && let start_offset = BytePos::from_u32(match lit.kind {
+                LitKind::Str => 1,
+                LitKind::ByteStr | LitKind::CStr => 2,
+                _ => return,
+            })
+            && !in_external_macro(cx.sess(), expr.span)
+        {
+            let s = lit.symbol.as_str();
+            let mut iter = s.as_bytes().iter();
+            while let Some(&c) = iter.next() {
+                if c == b'\\'
+                    // Always move the iterator to read the escape char.
+                    && let Some(b'0') = iter.next()
+                {
+                    // C-style octal escapes read from one to three characters.
+                    // The first character (`0`) has already been read.
+                    let (tail, len, c_hi, c_lo) = match *iter.as_slice() {
+                        [c_hi @ b'0'..=b'7', c_lo @ b'0'..=b'7', ref tail @ ..] => (tail, 4, c_hi, c_lo),
+                        [c_lo @ b'0'..=b'7', ref tail @ ..] => (tail, 3, b'0', c_lo),
+                        _ => continue,
+                    };
+                    iter = tail.iter();
+                    let offset = start_offset + BytePos::from_usize(s.len() - tail.len());
+                    let data = expr.span.data();
+                    let span = SpanData {
+                        lo: data.lo + offset - BytePos::from_u32(len),
+                        hi: data.lo + offset,
+                        ..data
+                    }
+                    .span();
 
-    // go through the string, looking for \0[0-7][0-7]?
-    while let Some((from, ch)) = iter.next() {
-        if ch == '\\' {
-            if let Some((_, '0')) = iter.next() {
-                // collect up to two further octal digits
-                if let Some((mut to, _)) = iter.next_if(|(_, ch)| matches!(ch, '0'..='7')) {
-                    if iter.next_if(|(_, ch)| matches!(ch, '0'..='7')).is_some() {
-                        to += 1;
+                    // Last check to make sure the source text matches what we read from the string.
+                    // Macros are involved somehow if this doesn't match.
+                    if span.check_source_text(cx, |src| match *src.as_bytes() {
+                        [b'\\', b'0', lo] => lo == c_lo,
+                        [b'\\', b'0', hi, lo] => hi == c_hi && lo == c_lo,
+                        _ => false,
+                    }) {
+                        span_lint_and_then(cx, OCTAL_ESCAPES, span, "octal-looking escape in a literal", |diag| {
+                            diag.help_once("octal escapes are not supported, `\\0` is always null")
+                                .span_suggestion(
+                                    span,
+                                    "if an octal escape is intended, use a hex escape instead",
+                                    format!("\\x{:02x}", (((c_hi - b'0') << 3) | (c_lo - b'0'))),
+                                    Applicability::MaybeIncorrect,
+                                )
+                                .span_suggestion(
+                                    span,
+                                    "if a null escape is intended, disambiguate using",
+                                    format!("\\x00{}{}", c_hi as char, c_lo as char),
+                                    Applicability::MaybeIncorrect,
+                                );
+                        });
+                    } else {
+                        break;
                     }
-                    found.push((from, to + 1));
                 }
             }
         }
     }
-
-    if found.is_empty() {
-        return;
-    }
-
-    span_lint_and_then(
-        cx,
-        OCTAL_ESCAPES,
-        span,
-        format!(
-            "octal-looking escape in {} literal",
-            if is_string { "string" } else { "byte string" }
-        ),
-        |diag| {
-            diag.help(format!(
-                "octal escapes are not supported, `\\0` is always a null {}",
-                if is_string { "character" } else { "byte" }
-            ));
-
-            // Generate suggestions if the string is not too long (~ 5 lines)
-            if contents.len() < 400 {
-                // construct two suggestion strings, one with \x escapes with octal meaning
-                // as in C, and one with \x00 for null bytes.
-                let mut suggest_1 = if is_string { "\"" } else { "b\"" }.to_string();
-                let mut suggest_2 = suggest_1.clone();
-                let mut index = 0;
-                for (from, to) in found {
-                    suggest_1.push_str(&contents[index..from]);
-                    suggest_2.push_str(&contents[index..from]);
-
-                    // construct a replacement escape
-                    // the maximum value is \077, or \x3f, so u8 is sufficient here
-                    if let Ok(n) = u8::from_str_radix(&contents[from + 1..to], 8) {
-                        write!(suggest_1, "\\x{n:02x}").unwrap();
-                    }
-
-                    // append the null byte as \x00 and the following digits literally
-                    suggest_2.push_str("\\x00");
-                    suggest_2.push_str(&contents[from + 2..to]);
-
-                    index = to;
-                }
-                suggest_1.push_str(&contents[index..]);
-                suggest_2.push_str(&contents[index..]);
-
-                suggest_1.push('"');
-                suggest_2.push('"');
-                // suggestion 1: equivalent hex escape
-                diag.span_suggestion(
-                    span,
-                    "if an octal escape was intended, use the hexadecimal representation instead",
-                    suggest_1,
-                    Applicability::MaybeIncorrect,
-                );
-                // suggestion 2: unambiguous null byte
-                diag.span_suggestion(
-                    span,
-                    format!(
-                        "if the null {} is intended, disambiguate using",
-                        if is_string { "character" } else { "byte" }
-                    ),
-                    suggest_2,
-                    Applicability::MaybeIncorrect,
-                );
-            }
-        },
-    );
 }
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 0561739d160..faab79de9d3 100644
--- a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
@@ -86,6 +86,7 @@ fn get_lint_and_message(is_local: bool, is_comparing_arrays: bool) -> (&'static
 
 fn is_allowed(val: &Constant<'_>) -> bool {
     match val {
+        // FIXME(f16_f128): add when equality check is available on all platforms
         &Constant::F32(f) => f == 0.0 || f.is_infinite(),
         &Constant::F64(f) => f == 0.0 || f.is_infinite(),
         Constant::Vec(vec) => vec.iter().all(|f| match f {
diff --git a/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs
index c56518ac72a..d65fffac5a8 100644
--- a/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs
@@ -79,6 +79,7 @@ fn analyze_operand(operand: &Expr<'_>, cx: &LateContext<'_>, expr: &Expr<'_>) ->
             },
             _ => {},
         },
+        // FIXME(f16_f128): add when casting is available on all platforms
         Some(Constant::F32(f)) => {
             return Some(floating_point_operand_info(&f));
         },
diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs
index 186e548d373..4fdaa9f00a1 100644
--- a/src/tools/clippy/clippy_lints/src/ranges.rs
+++ b/src/tools/clippy/clippy_lints/src/ranges.rs
@@ -1,7 +1,7 @@
 use clippy_config::msrvs::{self, Msrv};
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability};
+use clippy_utils::source::{snippet, snippet_with_applicability, SpanRangeExt};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{get_parent_expr, higher, in_constant, is_integer_const, path_to_local};
 use rustc_ast::ast::RangeLimits;
@@ -285,9 +285,10 @@ fn check_possible_range_contains(
     if let ExprKind::Binary(ref lhs_op, _left, new_lhs) = left.kind
         && op == lhs_op.node
         && let new_span = Span::new(new_lhs.span.lo(), right.span.hi(), expr.span.ctxt(), expr.span.parent())
-        && let Some(snip) = &snippet_opt(cx, new_span)
-        // Do not continue if we have mismatched number of parens, otherwise the suggestion is wrong
-        && snip.matches('(').count() == snip.matches(')').count()
+        && new_span.check_source_text(cx, |src| {
+            // Do not continue if we have mismatched number of parens, otherwise the suggestion is wrong
+            src.matches('(').count() == src.matches(')').count()
+        })
     {
         check_possible_range_contains(cx, op, new_lhs, right, expr, new_span);
     }
@@ -363,17 +364,19 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
             |diag| {
                 let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").maybe_par().to_string());
                 let end = Sugg::hir(cx, y, "y").maybe_par();
-                if let Some(is_wrapped) = &snippet_opt(cx, span) {
-                    if is_wrapped.starts_with('(') && is_wrapped.ends_with(')') {
+                match span.with_source_text(cx, |src| src.starts_with('(') && src.ends_with(')')) {
+                    Some(true) => {
                         diag.span_suggestion(span, "use", format!("({start}..={end})"), Applicability::MaybeIncorrect);
-                    } else {
+                    },
+                    Some(false) => {
                         diag.span_suggestion(
                             span,
                             "use",
                             format!("{start}..={end}"),
                             Applicability::MachineApplicable, // snippet
                         );
-                    }
+                    },
+                    None => {},
                 }
             },
         );
diff --git a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
index 7f87d18e502..82f22ad693d 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
@@ -133,7 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
             } else if let Some(target_id) = cx.tcx.lang_items().deref_target() {
                 if let Ok(deref_ty) = cx.tcx.try_normalize_erasing_regions(
                     cx.param_env,
-                    Ty::new_projection(cx.tcx, target_id, cx.tcx.mk_args(&[GenericArg::from(indexed_ty)])),
+                    Ty::new_projection_from_args(cx.tcx, target_id, cx.tcx.mk_args(&[GenericArg::from(indexed_ty)])),
                 ) {
                     if deref_ty == expr_ty {
                         let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0;
diff --git a/src/tools/clippy/clippy_lints/src/string_patterns.rs b/src/tools/clippy/clippy_lints/src/string_patterns.rs
index 64b5b8f9f27..7ba58942a17 100644
--- a/src/tools/clippy/clippy_lints/src/string_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/string_patterns.rs
@@ -1,5 +1,6 @@
 use std::ops::ControlFlow;
 
+use clippy_config::msrvs::{self, Msrv};
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::eager_or_lazy::switch_to_eager_eval;
 use clippy_utils::macros::matching_root_macro_call;
@@ -12,7 +13,7 @@ use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
-use rustc_session::declare_lint_pass;
+use rustc_session::impl_lint_pass;
 use rustc_span::{sym, Span};
 
 declare_clippy_lint! {
@@ -69,7 +70,18 @@ declare_clippy_lint! {
     "using a single-character str where a char could be used, e.g., `_.split(\"x\")`"
 }
 
-declare_lint_pass!(StringPatterns => [MANUAL_PATTERN_CHAR_COMPARISON, SINGLE_CHAR_PATTERN]);
+pub struct StringPatterns {
+    msrv: Msrv,
+}
+
+impl StringPatterns {
+    #[must_use]
+    pub fn new(msrv: Msrv) -> Self {
+        Self { msrv }
+    }
+}
+
+impl_lint_pass!(StringPatterns => [MANUAL_PATTERN_CHAR_COMPARISON, SINGLE_CHAR_PATTERN]);
 
 const PATTERN_METHODS: [(&str, usize); 22] = [
     ("contains", 0),
@@ -122,7 +134,7 @@ fn get_char_span<'tcx>(cx: &'_ LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Optio
     }
 }
 
-fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr<'_>) {
+fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr<'_>, msrv: &Msrv) {
     if let ExprKind::Closure(closure) = method_arg.kind
         && let body = cx.tcx.hir().body(closure.body)
         && let Some(PatKind::Binding(_, binding, ..)) = body.params.first().map(|p| p.pat.kind)
@@ -178,6 +190,9 @@ fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr<
         {
             return;
         }
+        if set_char_spans.len() > 1 && !msrv.meets(msrvs::PATTERN_TRAIT_CHAR_ARRAY) {
+            return;
+        }
         span_lint_and_then(
             cx,
             MANUAL_PATTERN_CHAR_COMPARISON,
@@ -221,7 +236,9 @@ impl<'tcx> LateLintPass<'tcx> for StringPatterns {
         {
             check_single_char_pattern_lint(cx, arg);
 
-            check_manual_pattern_char_comparison(cx, arg);
+            check_manual_pattern_char_comparison(cx, arg, &self.msrv);
         }
     }
+
+    extract_msrv_attr!(LateContext);
 }
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
index ab1b3043f0c..1c1de805db0 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
@@ -549,7 +549,7 @@ fn ident_difference_expr_with_base_location(
         | (Assign(_, _, _), Assign(_, _, _))
         | (TryBlock(_), TryBlock(_))
         | (Await(_, _), Await(_, _))
-        | (Gen(_, _, _), Gen(_, _, _))
+        | (Gen(_, _, _, _), Gen(_, _, _, _))
         | (Block(_, _), Block(_, _))
         | (Closure(_), Closure(_))
         | (Match(_, _, _), Match(_, _, _))
diff --git a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
index 5e41b3f4914..6ba98a92423 100644
--- a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
@@ -15,7 +15,7 @@ use rustc_middle::ty::{self, AssocKind, Ty, TyCtxt};
 use rustc_session::impl_lint_pass;
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::{sym, Span};
-use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
+use rustc_trait_selection::error_reporting::traits::suggestions::ReturnsVisitor;
 
 declare_clippy_lint! {
     /// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
index f376d349646..72392f8e1f7 100644
--- a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
+++ b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_hir_and_then;
-use itertools::Itertools;
+use core::mem::replace;
 use rustc_errors::Applicability;
 use rustc_hir::{HirId, Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -56,55 +56,71 @@ impl UpperCaseAcronyms {
 
 impl_lint_pass!(UpperCaseAcronyms => [UPPER_CASE_ACRONYMS]);
 
-fn correct_ident(ident: &str) -> String {
-    let ident = ident.chars().rev().collect::<String>();
-    let fragments = ident
-        .split_inclusive(|x: char| !x.is_ascii_lowercase())
-        .rev()
-        .map(|x| x.chars().rev().collect::<String>());
-
-    let mut ident = fragments.clone().next().unwrap();
-    for (ref prev, ref curr) in fragments.tuple_windows() {
-        if <[&String; 2]>::from((prev, curr))
-            .iter()
-            .all(|s| s.len() == 1 && s.chars().next().unwrap().is_ascii_uppercase())
-        {
-            ident.push_str(&curr.to_ascii_lowercase());
+fn contains_acronym(s: &str) -> bool {
+    let mut count = 0;
+    for c in s.chars() {
+        if c.is_ascii_uppercase() {
+            count += 1;
+            if count == 3 {
+                return true;
+            }
         } else {
-            ident.push_str(curr);
+            count = 0;
         }
     }
-    ident
+    count == 2
 }
 
 fn check_ident(cx: &LateContext<'_>, ident: &Ident, hir_id: HirId, be_aggressive: bool) {
-    let span = ident.span;
-    let ident = ident.as_str();
-    let corrected = correct_ident(ident);
-    // warn if we have pure-uppercase idents
-    // assume that two-letter words are some kind of valid abbreviation like FP for false positive
-    // (and don't warn)
-    if (ident.chars().all(|c| c.is_ascii_uppercase()) && ident.len() > 2)
-    // otherwise, warn if we have SOmeTHING lIKE THIs but only warn with the aggressive
-    // upper-case-acronyms-aggressive config option enabled
-    || (be_aggressive && ident != corrected)
+    let s = ident.as_str();
+
+    // By default, only warn for upper case identifiers with at least 3 characters.
+    let replacement = if s.len() > 2 && s.bytes().all(|c| c.is_ascii_uppercase()) {
+        let mut r = String::with_capacity(s.len());
+        let mut s = s.chars();
+        r.push(s.next().unwrap());
+        r.extend(s.map(|c| c.to_ascii_lowercase()));
+        r
+    } else if be_aggressive
+        // Only lint if the ident starts with an upper case character.
+        && let unprefixed = s.trim_start_matches('_')
+        && unprefixed.starts_with(|c: char| c.is_ascii_uppercase())
+        && contains_acronym(unprefixed)
     {
-        span_lint_hir_and_then(
-            cx,
-            UPPER_CASE_ACRONYMS,
-            hir_id,
-            span,
-            format!("name `{ident}` contains a capitalized acronym"),
-            |diag| {
-                diag.span_suggestion(
-                    span,
-                    "consider making the acronym lowercase, except the initial letter",
-                    corrected,
-                    Applicability::MaybeIncorrect,
-                );
-            },
-        );
-    }
+        let mut r = String::with_capacity(s.len());
+        let mut s = s.chars();
+        let mut prev_upper = false;
+        while let Some(c) = s.next() {
+            r.push(
+                if replace(&mut prev_upper, c.is_ascii_uppercase())
+                    && s.clone().next().map_or(true, |c| c.is_ascii_uppercase())
+                {
+                    c.to_ascii_lowercase()
+                } else {
+                    c
+                },
+            );
+        }
+        r
+    } else {
+        return;
+    };
+
+    span_lint_hir_and_then(
+        cx,
+        UPPER_CASE_ACRONYMS,
+        hir_id,
+        ident.span,
+        format!("name `{ident}` contains a capitalized acronym"),
+        |diag| {
+            diag.span_suggestion(
+                ident.span,
+                "consider making the acronym lowercase, except the initial letter",
+                replacement,
+                Applicability::MaybeIncorrect,
+            );
+        },
+    );
 }
 
 impl LateLintPass<'_> for UpperCaseAcronyms {
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
index c62ae8d718d..0beb0bb8ed4 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
@@ -69,6 +69,7 @@ pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
         SimplifiedType::Float(FloatTy::F64),
         SimplifiedType::Slice,
         SimplifiedType::Str,
+        SimplifiedType::Bool,
     ]
     .iter()
     .flat_map(|&ty| cx.tcx.incoherent_impls(ty).into_iter())
diff --git a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
index 662242f6196..60d8a13d359 100644
--- a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
@@ -38,6 +38,7 @@ impl<'tcx> LateLintPass<'tcx> for ZeroDiv {
             // do something like 0.0/(2.0 - 2.0), but it would be nice to warn on that case too.
             && let Some(lhs_value) = constant_simple(cx, cx.typeck_results(), left)
             && let Some(rhs_value) = constant_simple(cx, cx.typeck_results(), right)
+            // FIXME(f16_f128): add these types when eq is available on all platforms
             && (Constant::F32(0.0) == lhs_value || Constant::F64(0.0) == lhs_value)
             && (Constant::F32(0.0) == rhs_value || Constant::F64(0.0) == rhs_value)
         {
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index 3a3aeb88216..6e53ff3ee6e 100644
--- a/src/tools/clippy/clippy_utils/Cargo.toml
+++ b/src/tools/clippy/clippy_utils/Cargo.toml
@@ -9,6 +9,8 @@ clippy_config = { path = "../clippy_config" }
 arrayvec = { version = "0.7", default-features = false }
 itertools = "0.12"
 rustc-semver = "1.1"
+# FIXME(f16_f128): remove when no longer needed for parsing
+rustc_apfloat = "0.2.0"
 
 [features]
 deny-warnings = ["clippy_config/deny-warnings"]
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index fb43f7d80af..181bbdde8e5 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -226,7 +226,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
                 && eq_fn_decl(lf, rf)
                 && eq_expr(le, re)
         },
-        (Gen(lc, lb, lk), Gen(rc, rb, rk)) => lc == rc && eq_block(lb, rb) && lk == rk,
+        (Gen(lc, lb, lk, _), Gen(rc, rb, rk, _)) => lc == rc && eq_block(lb, rb) && lk == rk,
         (Range(lf, lt, ll), Range(rf, rt, rl)) => ll == rl && eq_expr_opt(lf, rf) && eq_expr_opt(lt, rt),
         (AddrOf(lbk, lm, le), AddrOf(rbk, rm, re)) => lbk == rbk && lm == rm && eq_expr(le, re),
         (Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp),
@@ -449,13 +449,13 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool {
     use ForeignItemKind::*;
     match (l, r) {
         (
-            Static(box StaticForeignItem {
+            Static(box StaticItem {
                 ty: lt,
                 mutability: lm,
                 expr: le,
                 safety: ls,
             }),
-            Static(box StaticForeignItem {
+            Static(box StaticItem {
                 ty: rt,
                 mutability: rm,
                 expr: re,
@@ -724,9 +724,7 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool {
         (Tup(l), Tup(r)) => over(l, r, |l, r| eq_ty(l, r)),
         (Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp),
         (TraitObject(lg, ls), TraitObject(rg, rs)) => ls == rs && over(lg, rg, eq_generic_bound),
-        (ImplTrait(_, lg), ImplTrait(_, rg)) => {
-            over(lg, rg, eq_generic_bound)
-        },
+        (ImplTrait(_, lg), ImplTrait(_, rg)) => over(lg, rg, eq_generic_bound),
         (Typeof(l), Typeof(r)) => eq_expr(&l.value, &r.value),
         (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
         _ => false,
diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
index 553e8999975..7f2234b310b 100644
--- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
+++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
@@ -18,8 +18,8 @@ use rustc_ast::AttrStyle;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
     Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, FnRetTy, HirId, Impl,
-    ImplItem, ImplItemKind, IsAuto, Item, ItemKind, LoopSource, MatchSource, MutTy, Node, QPath, Safety, TraitItem,
-    TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, YieldSource,
+    ImplItem, ImplItemKind, IsAuto, Item, ItemKind, Lit, LoopSource, MatchSource, MutTy, Node, Path, QPath, Safety,
+    TraitItem, TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, YieldSource,
 };
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::ty::TyCtxt;
@@ -121,6 +121,26 @@ fn qpath_search_pat(path: &QPath<'_>) -> (Pat, Pat) {
     }
 }
 
+fn path_search_pat(path: &Path<'_>) -> (Pat, Pat) {
+    let (head, tail) = match path.segments {
+        [head, .., tail] => (head, tail),
+        [p] => (p, p),
+        [] => return (Pat::Str(""), Pat::Str("")),
+    };
+    (
+        if head.ident.name == kw::PathRoot {
+            Pat::Str("::")
+        } else {
+            Pat::Sym(head.ident.name)
+        },
+        if tail.args.is_some() {
+            Pat::Str(">")
+        } else {
+            Pat::Sym(tail.ident.name)
+        },
+    )
+}
+
 /// Get the search patterns to use for the given expression
 fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) {
     match e.kind {
@@ -355,19 +375,21 @@ fn ty_search_pat(ty: &Ty<'_>) -> (Pat, Pat) {
     }
 }
 
+fn ident_search_pat(ident: Ident) -> (Pat, Pat) {
+    (Pat::Sym(ident.name), Pat::Sym(ident.name))
+}
+
 pub trait WithSearchPat<'cx> {
     type Context: LintContext;
     fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat);
     fn span(&self) -> Span;
 }
 macro_rules! impl_with_search_pat {
-    ($cx:ident: $ty:ident with $fn:ident $(($tcx:ident))?) => {
-        impl<'cx> WithSearchPat<'cx> for $ty<'cx> {
-            type Context = $cx<'cx>;
-            #[allow(unused_variables)]
-            fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat) {
-                $(let $tcx = cx.tcx;)?
-                $fn($($tcx,)? self)
+    (($cx_ident:ident: $cx_ty:ident<$cx_lt:lifetime>, $self:tt: $ty:ty) => $fn:ident($($args:tt)*)) => {
+        impl<$cx_lt> WithSearchPat<$cx_lt> for $ty {
+            type Context = $cx_ty<$cx_lt>;
+            fn search_pat(&$self, $cx_ident: &Self::Context) -> (Pat, Pat) {
+                $fn($($args)*)
             }
             fn span(&self) -> Span {
                 self.span
@@ -375,13 +397,17 @@ macro_rules! impl_with_search_pat {
         }
     };
 }
-impl_with_search_pat!(LateContext: Expr with expr_search_pat(tcx));
-impl_with_search_pat!(LateContext: Item with item_search_pat);
-impl_with_search_pat!(LateContext: TraitItem with trait_item_search_pat);
-impl_with_search_pat!(LateContext: ImplItem with impl_item_search_pat);
-impl_with_search_pat!(LateContext: FieldDef with field_def_search_pat);
-impl_with_search_pat!(LateContext: Variant with variant_search_pat);
-impl_with_search_pat!(LateContext: Ty with ty_search_pat);
+impl_with_search_pat!((cx: LateContext<'tcx>, self: Expr<'tcx>) => expr_search_pat(cx.tcx, self));
+impl_with_search_pat!((_cx: LateContext<'tcx>, self: Item<'_>) => item_search_pat(self));
+impl_with_search_pat!((_cx: LateContext<'tcx>, self: TraitItem<'_>) => trait_item_search_pat(self));
+impl_with_search_pat!((_cx: LateContext<'tcx>, self: ImplItem<'_>) => impl_item_search_pat(self));
+impl_with_search_pat!((_cx: LateContext<'tcx>, self: FieldDef<'_>) => field_def_search_pat(self));
+impl_with_search_pat!((_cx: LateContext<'tcx>, self: Variant<'_>) => variant_search_pat(self));
+impl_with_search_pat!((_cx: LateContext<'tcx>, self: Ty<'_>) => ty_search_pat(self));
+impl_with_search_pat!((_cx: LateContext<'tcx>, self: Attribute) => attr_search_pat(self));
+impl_with_search_pat!((_cx: LateContext<'tcx>, self: Ident) => ident_search_pat(*self));
+impl_with_search_pat!((_cx: LateContext<'tcx>, self: Lit) => lit_search_pat(&self.node));
+impl_with_search_pat!((_cx: LateContext<'tcx>, self: Path<'_>) => path_search_pat(self));
 
 impl<'cx> WithSearchPat<'cx> for (&FnKind<'cx>, &Body<'cx>, HirId, Span) {
     type Context = LateContext<'cx>;
@@ -395,32 +421,6 @@ impl<'cx> WithSearchPat<'cx> for (&FnKind<'cx>, &Body<'cx>, HirId, Span) {
     }
 }
 
-// `Attribute` does not have the `hir` associated lifetime, so we cannot use the macro
-impl<'cx> WithSearchPat<'cx> for &'cx Attribute {
-    type Context = LateContext<'cx>;
-
-    fn search_pat(&self, _cx: &Self::Context) -> (Pat, Pat) {
-        attr_search_pat(self)
-    }
-
-    fn span(&self) -> Span {
-        self.span
-    }
-}
-
-// `Ident` does not have the `hir` associated lifetime, so we cannot use the macro
-impl<'cx> WithSearchPat<'cx> for Ident {
-    type Context = LateContext<'cx>;
-
-    fn search_pat(&self, _cx: &Self::Context) -> (Pat, Pat) {
-        (Pat::Sym(self.name), Pat::Sym(self.name))
-    }
-
-    fn span(&self) -> Span {
-        self.span
-    }
-}
-
 /// Checks if the item likely came from a proc-macro.
 ///
 /// This should be called after `in_external_macro` and the initial pattern matching of the ast as
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index cfd142fe1ff..de6ccfe476f 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -1,8 +1,11 @@
 #![allow(clippy::float_cmp)]
 
-use crate::source::{get_source_text, walk_span_to_context};
+use crate::macros::HirNode;
+use crate::source::{walk_span_to_context, SpanRangeExt};
 use crate::{clip, is_direct_expn_of, sext, unsext};
 
+use rustc_apfloat::ieee::{Half, Quad};
+use rustc_apfloat::Float;
 use rustc_ast::ast::{self, LitFloatType, LitKind};
 use rustc_data_structures::sync::Lrc;
 use rustc_hir::def::{DefKind, Res};
@@ -15,7 +18,7 @@ use rustc_middle::ty::{self, EarlyBinder, FloatTy, GenericArgsRef, IntTy, List,
 use rustc_middle::{bug, mir, span_bug};
 use rustc_span::def_id::DefId;
 use rustc_span::symbol::{Ident, Symbol};
-use rustc_span::SyntaxContext;
+use rustc_span::{sym, SyntaxContext};
 use rustc_target::abi::Size;
 use std::cmp::Ordering;
 use std::hash::{Hash, Hasher};
@@ -33,10 +36,14 @@ pub enum Constant<'tcx> {
     Char(char),
     /// An integer's bit representation.
     Int(u128),
+    /// An `f16`.
+    F16(f16),
     /// An `f32`.
     F32(f32),
     /// An `f64`.
     F64(f64),
+    /// An `f128`.
+    F128(f128),
     /// `true` or `false`.
     Bool(bool),
     /// An array of constants.
@@ -161,12 +168,19 @@ impl<'tcx> Hash for Constant<'tcx> {
             Self::Int(i) => {
                 i.hash(state);
             },
+            Self::F16(f) => {
+                // FIXME(f16_f128): once conversions to/from `f128` are available on all platforms,
+                f.to_bits().hash(state);
+            },
             Self::F32(f) => {
                 f64::from(f).to_bits().hash(state);
             },
             Self::F64(f) => {
                 f.to_bits().hash(state);
             },
+            Self::F128(f) => {
+                f.to_bits().hash(state);
+            },
             Self::Bool(b) => {
                 b.hash(state);
             },
@@ -268,6 +282,16 @@ impl<'tcx> Constant<'tcx> {
         }
         self
     }
+
+    fn parse_f16(s: &str) -> Self {
+        let f: Half = s.parse().unwrap();
+        Self::F16(f16::from_bits(f.to_bits().try_into().unwrap()))
+    }
+
+    fn parse_f128(s: &str) -> Self {
+        let f: Quad = s.parse().unwrap();
+        Self::F128(f128::from_bits(f.to_bits()))
+    }
 }
 
 /// Parses a `LitKind` to a `Constant`.
@@ -279,16 +303,17 @@ pub fn lit_to_mir_constant<'tcx>(lit: &LitKind, ty: Option<Ty<'tcx>>) -> Constan
         LitKind::Char(c) => Constant::Char(c),
         LitKind::Int(n, _) => Constant::Int(n.get()),
         LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty {
-            ast::FloatTy::F16 => unimplemented!("f16_f128"),
+            // FIXME(f16_f128): just use `parse()` directly when available for `f16`/`f128`
+            ast::FloatTy::F16 => Constant::parse_f16(is.as_str()),
             ast::FloatTy::F32 => Constant::F32(is.as_str().parse().unwrap()),
             ast::FloatTy::F64 => Constant::F64(is.as_str().parse().unwrap()),
-            ast::FloatTy::F128 => unimplemented!("f16_f128"),
+            ast::FloatTy::F128 => Constant::parse_f128(is.as_str()),
         },
         LitKind::Float(ref is, LitFloatType::Unsuffixed) => match ty.expect("type of float is known").kind() {
-            ty::Float(FloatTy::F16) => unimplemented!("f16_f128"),
+            ty::Float(FloatTy::F16) => Constant::parse_f16(is.as_str()),
             ty::Float(FloatTy::F32) => Constant::F32(is.as_str().parse().unwrap()),
             ty::Float(FloatTy::F64) => Constant::F64(is.as_str().parse().unwrap()),
-            ty::Float(FloatTy::F128) => unimplemented!("f16_f128"),
+            ty::Float(FloatTy::F128) => Constant::parse_f128(is.as_str()),
             _ => bug!(),
         },
         LitKind::Bool(b) => Constant::Bool(b),
@@ -302,6 +327,8 @@ pub enum ConstantSource {
     Local,
     /// The value is dependent on a defined constant.
     Constant,
+    /// The value is dependent on a constant defined in `core` crate.
+    CoreConstant,
 }
 impl ConstantSource {
     pub fn is_local(&self) -> bool {
@@ -415,9 +442,19 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
             ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.lcx.tcx.hir().body(body).value),
             ExprKind::DropTemps(e) => self.expr(e),
             ExprKind::Path(ref qpath) => {
+                let is_core_crate = if let Some(def_id) = self.lcx.qpath_res(qpath, e.hir_id()).opt_def_id() {
+                    self.lcx.tcx.crate_name(def_id.krate) == sym::core
+                } else {
+                    false
+                };
                 self.fetch_path_and_apply(qpath, e.hir_id, self.typeck_results.expr_ty(e), |this, result| {
                     let result = mir_to_const(this.lcx, result)?;
-                    this.source = ConstantSource::Constant;
+                    // If source is already Constant we wouldn't want to override it with CoreConstant
+                    this.source = if is_core_crate && !matches!(this.source, ConstantSource::Constant) {
+                        ConstantSource::CoreConstant
+                    } else {
+                        ConstantSource::Constant
+                    };
                     Some(result)
                 })
             },
@@ -625,15 +662,19 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
 
         match (lhs, index) {
             (Some(Constant::Vec(vec)), Some(Constant::Int(index))) => match vec.get(index as usize) {
+                Some(Constant::F16(x)) => Some(Constant::F16(*x)),
                 Some(Constant::F32(x)) => Some(Constant::F32(*x)),
                 Some(Constant::F64(x)) => Some(Constant::F64(*x)),
+                Some(Constant::F128(x)) => Some(Constant::F128(*x)),
                 _ => None,
             },
             (Some(Constant::Vec(vec)), _) => {
                 if !vec.is_empty() && vec.iter().all(|x| *x == vec[0]) {
                     match vec.first() {
+                        Some(Constant::F16(x)) => Some(Constant::F16(*x)),
                         Some(Constant::F32(x)) => Some(Constant::F32(*x)),
                         Some(Constant::F64(x)) => Some(Constant::F64(*x)),
+                        Some(Constant::F128(x)) => Some(Constant::F128(*x)),
                         _ => None,
                     }
                 } else {
@@ -655,7 +696,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
                 if let Some(expr_span) = walk_span_to_context(expr.span, span.ctxt)
                     && let expr_lo = expr_span.lo()
                     && expr_lo >= span.lo
-                    && let Some(src) = get_source_text(self.lcx, span.lo..expr_lo)
+                    && let Some(src) = (span.lo..expr_lo).get_source_text(self.lcx)
                     && let Some(src) = src.as_str()
                 {
                     use rustc_lexer::TokenKind::{BlockComment, LineComment, OpenBrace, Semi, Whitespace};
@@ -760,6 +801,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
                 },
                 _ => None,
             },
+            // FIXME(f16_f128): add these types when binary operations are available on all platforms
             (Constant::F32(l), Some(Constant::F32(r))) => match op.node {
                 BinOpKind::Add => Some(Constant::F32(l + r)),
                 BinOpKind::Sub => Some(Constant::F32(l - r)),
@@ -813,8 +855,10 @@ pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) ->
             ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)),
             ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)),
             ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.to_bits(int.size()))),
+            ty::Float(FloatTy::F16) => Some(Constant::F16(f16::from_bits(int.into()))),
             ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits(int.into()))),
             ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits(int.into()))),
+            ty::Float(FloatTy::F128) => Some(Constant::F128(f128::from_bits(int.into()))),
             ty::RawPtr(_, _) => Some(Constant::RawPtr(int.to_bits(int.size()))),
             _ => None,
         },
@@ -835,10 +879,10 @@ pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) ->
                 let range = alloc_range(offset + size * idx, size);
                 let val = alloc.read_scalar(&lcx.tcx, range, /* read_provenance */ false).ok()?;
                 res.push(match flt {
-                    FloatTy::F16 => unimplemented!("f16_f128"),
+                    FloatTy::F16 => Constant::F16(f16::from_bits(val.to_u16().ok()?)),
                     FloatTy::F32 => Constant::F32(f32::from_bits(val.to_u32().ok()?)),
                     FloatTy::F64 => Constant::F64(f64::from_bits(val.to_u64().ok()?)),
-                    FloatTy::F128 => unimplemented!("f16_f128"),
+                    FloatTy::F128 => Constant::F128(f128::from_bits(val.to_u128().ok()?)),
                 });
             }
             Some(Constant::Vec(res))
diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs
index 801a9852159..277ba8427e0 100644
--- a/src/tools/clippy/clippy_utils/src/higher.rs
+++ b/src/tools/clippy/clippy_utils/src/higher.rs
@@ -218,51 +218,56 @@ pub struct Range<'a> {
 
 impl<'a> Range<'a> {
     /// Higher a `hir` range to something similar to `ast::ExprKind::Range`.
+    #[allow(clippy::similar_names)]
     pub fn hir(expr: &'a Expr<'_>) -> Option<Range<'a>> {
-        /// Finds the field named `name` in the field. Always return `Some` for
-        /// convenience.
-        fn get_field<'c>(name: &str, fields: &'c [hir::ExprField<'_>]) -> Option<&'c Expr<'c>> {
-            let expr = &fields.iter().find(|field| field.ident.name.as_str() == name)?.expr;
-            Some(expr)
-        }
-
         match expr.kind {
-            ExprKind::Call(path, args)
+            ExprKind::Call(path, [arg1, arg2])
                 if matches!(
                     path.kind,
                     ExprKind::Path(QPath::LangItem(hir::LangItem::RangeInclusiveNew, ..))
                 ) =>
             {
                 Some(Range {
-                    start: Some(&args[0]),
-                    end: Some(&args[1]),
+                    start: Some(arg1),
+                    end: Some(arg2),
                     limits: ast::RangeLimits::Closed,
                 })
             },
-            ExprKind::Struct(path, fields, None) => match &path {
-                QPath::LangItem(hir::LangItem::RangeFull, ..) => Some(Range {
+            ExprKind::Struct(path, fields, None) => match (path, fields) {
+                (QPath::LangItem(hir::LangItem::RangeFull, ..), []) => Some(Range {
                     start: None,
                     end: None,
                     limits: ast::RangeLimits::HalfOpen,
                 }),
-                QPath::LangItem(hir::LangItem::RangeFrom, ..) => Some(Range {
-                    start: Some(get_field("start", fields)?),
-                    end: None,
-                    limits: ast::RangeLimits::HalfOpen,
-                }),
-                QPath::LangItem(hir::LangItem::Range, ..) => Some(Range {
-                    start: Some(get_field("start", fields)?),
-                    end: Some(get_field("end", fields)?),
-                    limits: ast::RangeLimits::HalfOpen,
-                }),
-                QPath::LangItem(hir::LangItem::RangeToInclusive, ..) => Some(Range {
-                    start: None,
-                    end: Some(get_field("end", fields)?),
-                    limits: ast::RangeLimits::Closed,
-                }),
-                QPath::LangItem(hir::LangItem::RangeTo, ..) => Some(Range {
+                (QPath::LangItem(hir::LangItem::RangeFrom, ..), [field]) if field.ident.name == sym::start => {
+                    Some(Range {
+                        start: Some(field.expr),
+                        end: None,
+                        limits: ast::RangeLimits::HalfOpen,
+                    })
+                },
+                (QPath::LangItem(hir::LangItem::Range, ..), [field1, field2]) => {
+                    let (start, end) = match (field1.ident.name, field2.ident.name) {
+                        (sym::start, sym::end) => (field1.expr, field2.expr),
+                        (sym::end, sym::start) => (field2.expr, field1.expr),
+                        _ => return None,
+                    };
+                    Some(Range {
+                        start: Some(start),
+                        end: Some(end),
+                        limits: ast::RangeLimits::HalfOpen,
+                    })
+                },
+                (QPath::LangItem(hir::LangItem::RangeToInclusive, ..), [field]) if field.ident.name == sym::end => {
+                    Some(Range {
+                        start: None,
+                        end: Some(field.expr),
+                        limits: ast::RangeLimits::Closed,
+                    })
+                },
+                (QPath::LangItem(hir::LangItem::RangeTo, ..), [field]) if field.ident.name == sym::end => Some(Range {
                     start: None,
-                    end: Some(get_field("end", fields)?),
+                    end: Some(field.expr),
                     limits: ast::RangeLimits::HalfOpen,
                 }),
                 _ => None,
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 50dd8430ac0..8706cec5d38 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -1,6 +1,6 @@
 use crate::consts::constant_simple;
 use crate::macros::macro_backtrace;
-use crate::source::{get_source_text, snippet_opt, walk_span_to_context, SpanRange};
+use crate::source::{snippet_opt, walk_span_to_context, SpanRange, SpanRangeExt};
 use crate::tokenize_with_text;
 use rustc_ast::ast::InlineAsmTemplatePiece;
 use rustc_data_structures::fx::FxHasher;
@@ -1173,9 +1173,9 @@ fn eq_span_tokens(
     pred: impl Fn(TokenKind) -> bool,
 ) -> bool {
     fn f(cx: &LateContext<'_>, left: Range<BytePos>, right: Range<BytePos>, pred: impl Fn(TokenKind) -> bool) -> bool {
-        if let Some(lsrc) = get_source_text(cx, left)
+        if let Some(lsrc) = left.get_source_text(cx)
             && let Some(lsrc) = lsrc.as_str()
-            && let Some(rsrc) = get_source_text(cx, right)
+            && let Some(rsrc) = right.get_source_text(cx)
             && let Some(rsrc) = rsrc.as_str()
         {
             let pred = |t: &(_, _)| pred(t.0);
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 7dc341ec8d7..935a25d7931 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -1,9 +1,11 @@
 #![feature(array_chunks)]
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
+#![feature(f128)]
+#![feature(f16)]
 #![feature(if_let_guard)]
 #![feature(let_chains)]
-#![feature(lint_reasons)]
+#![cfg_attr(bootstrap, feature(lint_reasons))]
 #![feature(never_type)]
 #![feature(rustc_private)]
 #![feature(assert_matches)]
@@ -2664,13 +2666,80 @@ pub enum DefinedTy<'tcx> {
 /// The context an expressions value is used in.
 pub struct ExprUseCtxt<'tcx> {
     /// The parent node which consumes the value.
-    pub node: ExprUseNode<'tcx>,
+    pub node: Node<'tcx>,
+    /// The child id of the node the value came from.
+    pub child_id: HirId,
     /// Any adjustments applied to the type.
     pub adjustments: &'tcx [Adjustment<'tcx>],
-    /// Whether or not the type must unify with another code path.
+    /// Whether the type must unify with another code path.
     pub is_ty_unified: bool,
-    /// Whether or not the value will be moved before it's used.
+    /// Whether the value will be moved before it's used.
     pub moved_before_use: bool,
+    /// Whether the use site has the same `SyntaxContext` as the value.
+    pub same_ctxt: bool,
+}
+impl<'tcx> ExprUseCtxt<'tcx> {
+    pub fn use_node(&self, cx: &LateContext<'tcx>) -> ExprUseNode<'tcx> {
+        match self.node {
+            Node::LetStmt(l) => ExprUseNode::LetStmt(l),
+            Node::ExprField(field) => ExprUseNode::Field(field),
+
+            Node::Item(&Item {
+                kind: ItemKind::Static(..) | ItemKind::Const(..),
+                owner_id,
+                ..
+            })
+            | Node::TraitItem(&TraitItem {
+                kind: TraitItemKind::Const(..),
+                owner_id,
+                ..
+            })
+            | Node::ImplItem(&ImplItem {
+                kind: ImplItemKind::Const(..),
+                owner_id,
+                ..
+            }) => ExprUseNode::ConstStatic(owner_id),
+
+            Node::Item(&Item {
+                kind: ItemKind::Fn(..),
+                owner_id,
+                ..
+            })
+            | Node::TraitItem(&TraitItem {
+                kind: TraitItemKind::Fn(..),
+                owner_id,
+                ..
+            })
+            | Node::ImplItem(&ImplItem {
+                kind: ImplItemKind::Fn(..),
+                owner_id,
+                ..
+            }) => ExprUseNode::Return(owner_id),
+
+            Node::Expr(use_expr) => match use_expr.kind {
+                ExprKind::Ret(_) => ExprUseNode::Return(OwnerId {
+                    def_id: cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()),
+                }),
+
+                ExprKind::Closure(closure) => ExprUseNode::Return(OwnerId { def_id: closure.def_id }),
+                ExprKind::Call(func, args) => match args.iter().position(|arg| arg.hir_id == self.child_id) {
+                    Some(i) => ExprUseNode::FnArg(func, i),
+                    None => ExprUseNode::Callee,
+                },
+                ExprKind::MethodCall(name, _, args, _) => ExprUseNode::MethodArg(
+                    use_expr.hir_id,
+                    name.args,
+                    args.iter()
+                        .position(|arg| arg.hir_id == self.child_id)
+                        .map_or(0, |i| i + 1),
+                ),
+                ExprKind::Field(_, name) => ExprUseNode::FieldAccess(name),
+                ExprKind::AddrOf(kind, mutbl, _) => ExprUseNode::AddrOf(kind, mutbl),
+                _ => ExprUseNode::Other,
+            },
+            _ => ExprUseNode::Other,
+        }
+    }
 }
 
 /// The node which consumes a value.
@@ -2691,7 +2760,8 @@ pub enum ExprUseNode<'tcx> {
     Callee,
     /// Access of a field.
     FieldAccess(Ident),
-    Expr,
+    /// Borrow expression.
+    AddrOf(ast::BorrowKind, Mutability),
     Other,
 }
 impl<'tcx> ExprUseNode<'tcx> {
@@ -2768,26 +2838,25 @@ impl<'tcx> ExprUseNode<'tcx> {
                 let sig = cx.tcx.fn_sig(id).skip_binder();
                 Some(DefinedTy::Mir(cx.tcx.param_env(id).and(sig.input(i))))
             },
-            Self::LetStmt(_) | Self::FieldAccess(..) | Self::Callee | Self::Expr | Self::Other => None,
+            Self::LetStmt(_) | Self::FieldAccess(..) | Self::Callee | Self::Other | Self::AddrOf(..) => None,
         }
     }
 }
 
 /// Gets the context an expression's value is used in.
-pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> Option<ExprUseCtxt<'tcx>> {
+pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> ExprUseCtxt<'tcx> {
     let mut adjustments = [].as_slice();
     let mut is_ty_unified = false;
     let mut moved_before_use = false;
+    let mut same_ctxt = true;
     let ctxt = e.span.ctxt();
-    walk_to_expr_usage(cx, e, &mut |parent_id, parent, child_id| {
+    let node = walk_to_expr_usage(cx, e, &mut |parent_id, parent, child_id| -> ControlFlow<!> {
         if adjustments.is_empty()
             && let Node::Expr(e) = cx.tcx.hir_node(child_id)
         {
             adjustments = cx.typeck_results().expr_adjustments(e);
         }
-        if cx.tcx.hir().span(parent_id).ctxt() != ctxt {
-            return ControlFlow::Break(());
-        }
+        same_ctxt &= cx.tcx.hir().span(parent_id).ctxt() == ctxt;
         if let Node::Expr(e) = parent {
             match e.kind {
                 ExprKind::If(e, _, _) | ExprKind::Match(e, _, _) if e.hir_id != child_id => {
@@ -2803,71 +2872,26 @@ pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> Optio
             }
         }
         ControlFlow::Continue(())
-    })?
-    .continue_value()
-    .map(|(use_node, child_id)| {
-        let node = match use_node {
-            Node::LetStmt(l) => ExprUseNode::LetStmt(l),
-            Node::ExprField(field) => ExprUseNode::Field(field),
-
-            Node::Item(&Item {
-                kind: ItemKind::Static(..) | ItemKind::Const(..),
-                owner_id,
-                ..
-            })
-            | Node::TraitItem(&TraitItem {
-                kind: TraitItemKind::Const(..),
-                owner_id,
-                ..
-            })
-            | Node::ImplItem(&ImplItem {
-                kind: ImplItemKind::Const(..),
-                owner_id,
-                ..
-            }) => ExprUseNode::ConstStatic(owner_id),
-
-            Node::Item(&Item {
-                kind: ItemKind::Fn(..),
-                owner_id,
-                ..
-            })
-            | Node::TraitItem(&TraitItem {
-                kind: TraitItemKind::Fn(..),
-                owner_id,
-                ..
-            })
-            | Node::ImplItem(&ImplItem {
-                kind: ImplItemKind::Fn(..),
-                owner_id,
-                ..
-            }) => ExprUseNode::Return(owner_id),
-
-            Node::Expr(use_expr) => match use_expr.kind {
-                ExprKind::Ret(_) => ExprUseNode::Return(OwnerId {
-                    def_id: cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()),
-                }),
-                ExprKind::Closure(closure) => ExprUseNode::Return(OwnerId { def_id: closure.def_id }),
-                ExprKind::Call(func, args) => match args.iter().position(|arg| arg.hir_id == child_id) {
-                    Some(i) => ExprUseNode::FnArg(func, i),
-                    None => ExprUseNode::Callee,
-                },
-                ExprKind::MethodCall(name, _, args, _) => ExprUseNode::MethodArg(
-                    use_expr.hir_id,
-                    name.args,
-                    args.iter().position(|arg| arg.hir_id == child_id).map_or(0, |i| i + 1),
-                ),
-                ExprKind::Field(child, name) if child.hir_id == e.hir_id => ExprUseNode::FieldAccess(name),
-                _ => ExprUseNode::Expr,
-            },
-            _ => ExprUseNode::Other,
-        };
-        ExprUseCtxt {
+    });
+    match node {
+        Some(ControlFlow::Continue((node, child_id))) => ExprUseCtxt {
             node,
+            child_id,
             adjustments,
             is_ty_unified,
             moved_before_use,
-        }
-    })
+            same_ctxt,
+        },
+        Some(ControlFlow::Break(_)) => unreachable!("type of node is ControlFlow<!>"),
+        None => ExprUseCtxt {
+            node: Node::Crate(cx.tcx.hir().root_module()),
+            child_id: HirId::INVALID,
+            adjustments: &[],
+            is_ty_unified: true,
+            moved_before_use: true,
+            same_ctxt: false,
+        },
+    }
 }
 
 /// Tokenizes the input while keeping the text associated with each token.
diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
index 7b4fd8a210e..07e6705cd3d 100644
--- a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
+++ b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
@@ -69,7 +69,7 @@ impl<'a, 'b, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'b,
     fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _location: mir::Location) {
         let lhs = place.local;
         match rvalue {
-            mir::Rvalue::Ref(_, _, borrowed) => {
+            mir::Rvalue::Ref(_, _, borrowed) | mir::Rvalue::CopyForDeref(borrowed) => {
                 self.possible_borrower.add(borrowed.local, lhs);
             },
             other => {
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index 9bf068ee3cd..3f66813801d 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -110,5 +110,4 @@ pub const VEC_POP: [&str; 4] = ["alloc", "vec", "Vec", "pop"];
 pub const WAKER: [&str; 4] = ["core", "task", "wake", "Waker"];
 pub const OPTION_UNWRAP: [&str; 4] = ["core", "option", "Option", "unwrap"];
 pub const OPTION_EXPECT: [&str; 4] = ["core", "option", "Option", "expect"];
-#[expect(clippy::invalid_paths)] // not sure why it thinks this, it works so
 pub const BOOL_THEN: [&str; 4] = ["core", "bool", "<impl bool>", "then"];
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 42b10f69c0c..f206b2ceebc 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
@@ -330,7 +330,8 @@ fn check_terminator<'tcx>(
             target: _,
             unwind: _,
             fn_span: _,
-        } => {
+        }
+        | TerminatorKind::TailCall { func, args, fn_span: _ } => {
             let fn_ty = func.ty(body, tcx);
             if let ty::FnDef(fn_def_id, _) = *fn_ty.kind() {
                 if !is_const_fn(tcx, fn_def_id, msrv) {
diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs
index e2e5cde947d..496c8f5b553 100644
--- a/src/tools/clippy/clippy_utils/src/source.rs
+++ b/src/tools/clippy/clippy_utils/src/source.rs
@@ -9,12 +9,16 @@ use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource};
 use rustc_lint::{LateContext, LintContext};
 use rustc_session::Session;
 use rustc_span::source_map::{original_sp, SourceMap};
-use rustc_span::{hygiene, BytePos, SourceFileAndLine, Pos, SourceFile, Span, SpanData, SyntaxContext, DUMMY_SP};
+use rustc_span::{
+    hygiene, BytePos, FileNameDisplayPreference, Pos, SourceFile, SourceFileAndLine, Span, SpanData, SyntaxContext,
+    DUMMY_SP,
+};
 use std::borrow::Cow;
+use std::fmt;
 use std::ops::Range;
 
-/// A type which can be converted to the range portion of a `Span`.
-pub trait SpanRange {
+/// Conversion of a value into the range portion of a `Span`.
+pub trait SpanRange: Sized {
     fn into_range(self) -> Range<BytePos>;
 }
 impl SpanRange for Span {
@@ -34,6 +38,182 @@ impl SpanRange for Range<BytePos> {
     }
 }
 
+/// Conversion of a value into a `Span`
+pub trait IntoSpan: Sized {
+    fn into_span(self) -> Span;
+    fn with_ctxt(self, ctxt: SyntaxContext) -> Span;
+}
+impl IntoSpan for Span {
+    fn into_span(self) -> Span {
+        self
+    }
+    fn with_ctxt(self, ctxt: SyntaxContext) -> Span {
+        self.with_ctxt(ctxt)
+    }
+}
+impl IntoSpan for SpanData {
+    fn into_span(self) -> Span {
+        self.span()
+    }
+    fn with_ctxt(self, ctxt: SyntaxContext) -> Span {
+        Span::new(self.lo, self.hi, ctxt, self.parent)
+    }
+}
+impl IntoSpan for Range<BytePos> {
+    fn into_span(self) -> Span {
+        Span::with_root_ctxt(self.start, self.end)
+    }
+    fn with_ctxt(self, ctxt: SyntaxContext) -> Span {
+        Span::new(self.start, self.end, ctxt, None)
+    }
+}
+
+pub trait SpanRangeExt: SpanRange {
+    /// Gets the source file, and range in the file, of the given span. Returns `None` if the span
+    /// extends through multiple files, or is malformed.
+    fn get_source_text(self, cx: &impl LintContext) -> Option<SourceFileRange> {
+        get_source_text(cx.sess().source_map(), self.into_range())
+    }
+
+    /// Calls the given function with the source text referenced and returns the value. Returns
+    /// `None` if the source text cannot be retrieved.
+    fn with_source_text<T>(self, cx: &impl LintContext, f: impl for<'a> FnOnce(&'a str) -> T) -> Option<T> {
+        with_source_text(cx.sess().source_map(), self.into_range(), f)
+    }
+
+    /// Checks if the referenced source text satisfies the given predicate. Returns `false` if the
+    /// source text cannot be retrieved.
+    fn check_source_text(self, cx: &impl LintContext, pred: impl for<'a> FnOnce(&'a str) -> bool) -> bool {
+        self.with_source_text(cx, pred).unwrap_or(false)
+    }
+
+    /// Calls the given function with the both the text of the source file and the referenced range,
+    /// and returns the value. Returns `None` if the source text cannot be retrieved.
+    fn with_source_text_and_range<T>(
+        self,
+        cx: &impl LintContext,
+        f: impl for<'a> FnOnce(&'a str, Range<usize>) -> T,
+    ) -> Option<T> {
+        with_source_text_and_range(cx.sess().source_map(), self.into_range(), f)
+    }
+
+    /// Calls the given function with the both the text of the source file and the referenced range,
+    /// and creates a new span with the returned range. Returns `None` if the source text cannot be
+    /// retrieved, or no result is returned.
+    ///
+    /// The new range must reside within the same source file.
+    fn map_range(
+        self,
+        cx: &impl LintContext,
+        f: impl for<'a> FnOnce(&'a str, Range<usize>) -> Option<Range<usize>>,
+    ) -> Option<Range<BytePos>> {
+        map_range(cx.sess().source_map(), self.into_range(), f)
+    }
+
+    /// Extends the range to include all preceding whitespace characters.
+    fn with_leading_whitespace(self, cx: &impl LintContext) -> Range<BytePos> {
+        with_leading_whitespace(cx.sess().source_map(), self.into_range())
+    }
+
+    /// Trims the leading whitespace from the range.
+    fn trim_start(self, cx: &impl LintContext) -> Range<BytePos> {
+        trim_start(cx.sess().source_map(), self.into_range())
+    }
+
+    /// Writes the referenced source text to the given writer. Will return `Err` if the source text
+    /// could not be retrieved.
+    fn write_source_text_to(self, cx: &impl LintContext, dst: &mut impl fmt::Write) -> fmt::Result {
+        write_source_text_to(cx.sess().source_map(), self.into_range(), dst)
+    }
+
+    /// Extracts the referenced source text as an owned string.
+    fn source_text_to_string(self, cx: &impl LintContext) -> Option<String> {
+        self.with_source_text(cx, ToOwned::to_owned)
+    }
+}
+impl<T: SpanRange> SpanRangeExt for T {}
+
+fn get_source_text(sm: &SourceMap, sp: Range<BytePos>) -> Option<SourceFileRange> {
+    let start = sm.lookup_byte_offset(sp.start);
+    let end = sm.lookup_byte_offset(sp.end);
+    if !Lrc::ptr_eq(&start.sf, &end.sf) || start.pos > end.pos {
+        return None;
+    }
+    let range = start.pos.to_usize()..end.pos.to_usize();
+    Some(SourceFileRange { sf: start.sf, range })
+}
+
+fn with_source_text<T>(sm: &SourceMap, sp: Range<BytePos>, f: impl for<'a> FnOnce(&'a str) -> T) -> Option<T> {
+    if let Some(src) = get_source_text(sm, sp)
+        && let Some(src) = src.as_str()
+    {
+        Some(f(src))
+    } else {
+        None
+    }
+}
+
+fn with_source_text_and_range<T>(
+    sm: &SourceMap,
+    sp: Range<BytePos>,
+    f: impl for<'a> FnOnce(&'a str, Range<usize>) -> T,
+) -> Option<T> {
+    if let Some(src) = get_source_text(sm, sp)
+        && let Some(text) = &src.sf.src
+    {
+        Some(f(text, src.range))
+    } else {
+        None
+    }
+}
+
+#[expect(clippy::cast_possible_truncation)]
+fn map_range(
+    sm: &SourceMap,
+    sp: Range<BytePos>,
+    f: impl for<'a> FnOnce(&'a str, Range<usize>) -> Option<Range<usize>>,
+) -> Option<Range<BytePos>> {
+    if let Some(src) = get_source_text(sm, sp.clone())
+        && let Some(text) = &src.sf.src
+        && let Some(range) = f(text, src.range.clone())
+    {
+        debug_assert!(
+            range.start <= text.len() && range.end <= text.len(),
+            "Range `{range:?}` is outside the source file (file `{}`, length `{}`)",
+            src.sf.name.display(FileNameDisplayPreference::Local),
+            text.len(),
+        );
+        debug_assert!(range.start <= range.end, "Range `{range:?}` has overlapping bounds");
+        let dstart = (range.start as u32).wrapping_sub(src.range.start as u32);
+        let dend = (range.end as u32).wrapping_sub(src.range.start as u32);
+        Some(BytePos(sp.start.0.wrapping_add(dstart))..BytePos(sp.start.0.wrapping_add(dend)))
+    } else {
+        None
+    }
+}
+
+fn with_leading_whitespace(sm: &SourceMap, sp: Range<BytePos>) -> Range<BytePos> {
+    map_range(sm, sp.clone(), |src, range| {
+        Some(src.get(..range.start)?.trim_end().len()..range.end)
+    })
+    .unwrap_or(sp)
+}
+
+fn trim_start(sm: &SourceMap, sp: Range<BytePos>) -> Range<BytePos> {
+    map_range(sm, sp.clone(), |src, range| {
+        let src = src.get(range.clone())?;
+        Some(range.start + (src.len() - src.trim_start().len())..range.end)
+    })
+    .unwrap_or(sp)
+}
+
+fn write_source_text_to(sm: &SourceMap, sp: Range<BytePos>, dst: &mut impl fmt::Write) -> fmt::Result {
+    match with_source_text(sm, sp, |src| dst.write_str(src)) {
+        Some(x) => x,
+        None => Err(fmt::Error),
+    }
+}
+
 pub struct SourceFileRange {
     pub sf: Lrc<SourceFile>,
     pub range: Range<usize>,
@@ -46,21 +226,6 @@ impl SourceFileRange {
     }
 }
 
-/// Gets the source file, and range in the file, of the given span. Returns `None` if the span
-/// extends through multiple files, or is malformed.
-pub fn get_source_text(cx: &impl LintContext, sp: impl SpanRange) -> Option<SourceFileRange> {
-    fn f(sm: &SourceMap, sp: Range<BytePos>) -> Option<SourceFileRange> {
-        let start = sm.lookup_byte_offset(sp.start);
-        let end = sm.lookup_byte_offset(sp.end);
-        if !Lrc::ptr_eq(&start.sf, &end.sf) || start.pos > end.pos {
-            return None;
-        }
-        let range = start.pos.to_usize()..end.pos.to_usize();
-        Some(SourceFileRange { sf: start.sf, range })
-    }
-    f(cx.sess().source_map(), sp.into_range())
-}
-
 /// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`.
 pub fn expr_block<T: LintContext>(
     cx: &T,
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 7d4332a3d9d..acaeb93f44a 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -99,7 +99,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'
                     for (predicate, _span) in cx
                         .tcx
                         .explicit_item_super_predicates(def_id)
-                        .instantiate_identity_iter_copied()
+                        .iter_identity_copied()
                     {
                         match predicate.kind().skip_binder() {
                             // For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through
@@ -292,7 +292,7 @@ pub fn implements_trait_with_env_from_iter<'tcx>(
     let trait_ref = TraitRef::new(
         tcx,
         trait_id,
-        Some(GenericArg::from(ty)).into_iter().chain(args).chain(effect_arg),
+        [GenericArg::from(ty)].into_iter().chain(args).chain(effect_arg),
     );
 
     debug_assert_matches!(
@@ -1126,7 +1126,7 @@ pub fn make_projection<'tcx>(
         #[cfg(debug_assertions)]
         assert_generic_args_match(tcx, assoc_item.def_id, args);
 
-        Some(AliasTy::new(tcx, assoc_item.def_id, args))
+        Some(AliasTy::new_from_args(tcx, assoc_item.def_id, args))
     }
     helper(
         tcx,
@@ -1165,7 +1165,7 @@ pub fn make_normalized_projection<'tcx>(
             );
             return None;
         }
-        match tcx.try_normalize_erasing_regions(param_env, Ty::new_projection(tcx, ty.def_id, ty.args)) {
+        match tcx.try_normalize_erasing_regions(param_env, Ty::new_projection_from_args(tcx, ty.def_id, ty.args)) {
             Ok(ty) => Some(ty),
             Err(e) => {
                 debug_assert!(false, "failed to normalize type `{ty}`: {e:#?}");
@@ -1289,7 +1289,7 @@ pub fn make_normalized_projection_with_regions<'tcx>(
             .infer_ctxt()
             .build()
             .at(&cause, param_env)
-            .query_normalize(Ty::new_projection(tcx, ty.def_id, ty.args))
+            .query_normalize(Ty::new_projection_from_args(tcx, ty.def_id, ty.args))
         {
             Ok(ty) => Some(ty.value),
             Err(e) => {
@@ -1349,3 +1349,17 @@ pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_n
         None
     }
 }
+
+/// Get's the type of a field by name.
+pub fn get_field_by_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, name: Symbol) -> Option<Ty<'tcx>> {
+    match *ty.kind() {
+        ty::Adt(def, args) if def.is_union() || def.is_struct() => def
+            .non_enum_variant()
+            .fields
+            .iter()
+            .find(|f| f.name == name)
+            .map(|f| f.ty(tcx, args)),
+        ty::Tuple(args) => name.as_str().parse::<usize>().ok().and_then(|i| args.get(i).copied()),
+        _ => None,
+    }
+}
diff --git a/src/tools/clippy/lintcheck/Cargo.toml b/src/tools/clippy/lintcheck/Cargo.toml
index 8c5a409e25b..ae9e77b8eed 100644
--- a/src/tools/clippy/lintcheck/Cargo.toml
+++ b/src/tools/clippy/lintcheck/Cargo.toml
@@ -11,28 +11,19 @@ publish = false
 default-run = "lintcheck"
 
 [dependencies]
-anyhow = "1.0.69"
 cargo_metadata = "0.15.3"
 clap = { version = "4.4", features = ["derive", "env"] }
-crates_io_api = "0.8.1"
 crossbeam-channel = "0.5.6"
+diff = "0.1.13"
 flate2 = "1.0"
-indicatif = "0.17.3"
 rayon = "1.5.1"
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0.85"
+strip-ansi-escapes = "0.2.0"
 tar = "0.4"
 toml = "0.7.3"
-ureq = "2.2"
+ureq = { version = "2.2", features = ["json"] }
 walkdir = "2.3"
 
 [features]
 deny-warnings = []
-
-[[bin]]
-name = "lintcheck"
-path = "src/main.rs"
-
-[[bin]]
-name = "popular-crates"
-path = "src/popular-crates.rs"
diff --git a/src/tools/clippy/lintcheck/README.md b/src/tools/clippy/lintcheck/README.md
index 61b581ba0fa..2d6039caeef 100644
--- a/src/tools/clippy/lintcheck/README.md
+++ b/src/tools/clippy/lintcheck/README.md
@@ -26,11 +26,11 @@ the repo root.
 The results will then be saved to `lintcheck-logs/custom_logs.toml`.
 
 The `custom.toml` file may be built using <https://crates.io> recently most
-downloaded crates by using the `popular-crates` binary from the `lintcheck`
-directory. For example, to retrieve the 100 recently most downloaded crates:
+downloaded crates by using `cargo lintcheck popular`. For example, to retrieve
+the 200 recently most downloaded crates:
 
 ```
-cargo run --release --bin popular-crates -- -n 100 custom.toml
+cargo lintcheck popular -n 200 custom.toml
 ```
 
 
diff --git a/src/tools/clippy/lintcheck/src/config.rs b/src/tools/clippy/lintcheck/src/config.rs
index 3f712f453fa..e6cd7c9fdc2 100644
--- a/src/tools/clippy/lintcheck/src/config.rs
+++ b/src/tools/clippy/lintcheck/src/config.rs
@@ -1,8 +1,9 @@
-use clap::Parser;
+use clap::{Parser, Subcommand, ValueEnum};
 use std::num::NonZero;
 use std::path::PathBuf;
 
-#[derive(Clone, Debug, Parser)]
+#[derive(Parser, Clone, Debug)]
+#[command(args_conflicts_with_subcommands = true)]
 pub(crate) struct LintcheckConfig {
     /// Number of threads to use (default: all unless --fix or --recursive)
     #[clap(
@@ -35,12 +36,45 @@ pub(crate) struct LintcheckConfig {
     /// Apply a filter to only collect specified lints, this also overrides `allow` attributes
     #[clap(long = "filter", value_name = "clippy_lint_name", use_value_delimiter = true)]
     pub lint_filter: Vec<String>,
-    /// Change the reports table to use markdown links
-    #[clap(long)]
-    pub markdown: bool,
+    /// Set the output format of the log file
+    #[clap(long, short, default_value = "text")]
+    pub format: OutputFormat,
     /// Run clippy on the dependencies of crates specified in crates-toml
     #[clap(long, conflicts_with("max_jobs"))]
     pub recursive: bool,
+    #[command(subcommand)]
+    pub subcommand: Option<Commands>,
+}
+
+#[derive(Subcommand, Clone, Debug)]
+pub(crate) enum Commands {
+    /// Display a markdown diff between two lintcheck log files in JSON format
+    Diff { old: PathBuf, new: PathBuf },
+    /// Create a lintcheck crates TOML file containing the top N popular crates
+    Popular {
+        /// Output TOML file name
+        output: PathBuf,
+        /// Number of crate names to download
+        #[clap(short, long, default_value_t = 100)]
+        number: usize,
+    },
+}
+
+#[derive(ValueEnum, Debug, Clone, Copy, PartialEq, Eq)]
+pub(crate) enum OutputFormat {
+    Text,
+    Markdown,
+    Json,
+}
+
+impl OutputFormat {
+    fn file_extension(self) -> &'static str {
+        match self {
+            OutputFormat::Text => "txt",
+            OutputFormat::Markdown => "md",
+            OutputFormat::Json => "json",
+        }
+    }
 }
 
 impl LintcheckConfig {
@@ -53,7 +87,7 @@ impl LintcheckConfig {
         config.lintcheck_results_path = PathBuf::from(format!(
             "lintcheck-logs/{}_logs.{}",
             filename.display(),
-            if config.markdown { "md" } else { "txt" }
+            config.format.file_extension(),
         ));
 
         // look at the --threads arg, if 0 is passed, use the threads count
diff --git a/src/tools/clippy/lintcheck/src/json.rs b/src/tools/clippy/lintcheck/src/json.rs
new file mode 100644
index 00000000000..43d0413c7ce
--- /dev/null
+++ b/src/tools/clippy/lintcheck/src/json.rs
@@ -0,0 +1,122 @@
+use std::collections::HashMap;
+use std::fmt::Write;
+use std::fs;
+use std::hash::Hash;
+use std::path::Path;
+
+use crate::ClippyWarning;
+
+/// Creates the log file output for [`crate::config::OutputFormat::Json`]
+pub(crate) fn output(clippy_warnings: &[ClippyWarning]) -> String {
+    serde_json::to_string(&clippy_warnings).unwrap()
+}
+
+fn load_warnings(path: &Path) -> Vec<ClippyWarning> {
+    let file = fs::read(path).unwrap_or_else(|e| panic!("failed to read {}: {e}", path.display()));
+
+    serde_json::from_slice(&file).unwrap_or_else(|e| panic!("failed to deserialize {}: {e}", path.display()))
+}
+
+/// Group warnings by their primary span location + lint name
+fn create_map(warnings: &[ClippyWarning]) -> HashMap<impl Eq + Hash + '_, Vec<&ClippyWarning>> {
+    let mut map = HashMap::<_, Vec<_>>::with_capacity(warnings.len());
+
+    for warning in warnings {
+        let span = warning.span();
+        let key = (&warning.lint_type, &span.file_name, span.byte_start, span.byte_end);
+
+        map.entry(key).or_default().push(warning);
+    }
+
+    map
+}
+
+fn print_warnings(title: &str, warnings: &[&ClippyWarning]) {
+    if warnings.is_empty() {
+        return;
+    }
+
+    println!("### {title}");
+    println!("```");
+    for warning in warnings {
+        print!("{}", warning.diag);
+    }
+    println!("```");
+}
+
+fn print_changed_diff(changed: &[(&[&ClippyWarning], &[&ClippyWarning])]) {
+    fn render(warnings: &[&ClippyWarning]) -> String {
+        let mut rendered = String::new();
+        for warning in warnings {
+            write!(&mut rendered, "{}", warning.diag).unwrap();
+        }
+        rendered
+    }
+
+    if changed.is_empty() {
+        return;
+    }
+
+    println!("### Changed");
+    println!("```diff");
+    for &(old, new) in changed {
+        let old_rendered = render(old);
+        let new_rendered = render(new);
+
+        for change in diff::lines(&old_rendered, &new_rendered) {
+            use diff::Result::{Both, Left, Right};
+
+            match change {
+                Both(unchanged, _) => {
+                    println!(" {unchanged}");
+                },
+                Left(removed) => {
+                    println!("-{removed}");
+                },
+                Right(added) => {
+                    println!("+{added}");
+                },
+            }
+        }
+    }
+    println!("```");
+}
+
+pub(crate) fn diff(old_path: &Path, new_path: &Path) {
+    let old_warnings = load_warnings(old_path);
+    let new_warnings = load_warnings(new_path);
+
+    let old_map = create_map(&old_warnings);
+    let new_map = create_map(&new_warnings);
+
+    let mut added = Vec::new();
+    let mut removed = Vec::new();
+    let mut changed = Vec::new();
+
+    for (key, new) in &new_map {
+        if let Some(old) = old_map.get(key) {
+            if old != new {
+                changed.push((old.as_slice(), new.as_slice()));
+            }
+        } else {
+            added.extend(new);
+        }
+    }
+
+    for (key, old) in &old_map {
+        if !new_map.contains_key(key) {
+            removed.extend(old);
+        }
+    }
+
+    print!(
+        "{} added, {} removed, {} changed\n\n",
+        added.len(),
+        removed.len(),
+        changed.len()
+    );
+
+    print_warnings("Added", &added);
+    print_warnings("Removed", &removed);
+    print_changed_diff(&changed);
+}
diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs
index deb06094d83..ec72e0eb5dc 100644
--- a/src/tools/clippy/lintcheck/src/main.rs
+++ b/src/tools/clippy/lintcheck/src/main.rs
@@ -12,26 +12,29 @@
     unused_lifetimes,
     unused_qualifications
 )]
-#![allow(clippy::collapsible_else_if)]
+#![allow(clippy::collapsible_else_if, clippy::needless_borrows_for_generic_args)]
 
 mod config;
 mod driver;
+mod json;
+mod popular_crates;
 mod recursive;
 
-use crate::config::LintcheckConfig;
+use crate::config::{Commands, LintcheckConfig, OutputFormat};
 use crate::recursive::LintcheckServer;
 
 use std::collections::{HashMap, HashSet};
 use std::env::consts::EXE_SUFFIX;
-use std::fmt::{self, Write as _};
+use std::fmt::{self, Display, Write as _};
+use std::hash::Hash;
 use std::io::{self, ErrorKind};
 use std::path::{Path, PathBuf};
-use std::process::{Command, ExitStatus};
+use std::process::{Command, ExitStatus, Stdio};
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::time::Duration;
 use std::{env, fs, thread};
 
-use cargo_metadata::diagnostic::Diagnostic;
+use cargo_metadata::diagnostic::{Diagnostic, DiagnosticSpan};
 use cargo_metadata::Message;
 use rayon::prelude::*;
 use serde::{Deserialize, Serialize};
@@ -41,21 +44,21 @@ const LINTCHECK_DOWNLOADS: &str = "target/lintcheck/downloads";
 const LINTCHECK_SOURCES: &str = "target/lintcheck/sources";
 
 /// List of sources to check, loaded from a .toml file
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Deserialize)]
 struct SourceList {
     crates: HashMap<String, TomlCrate>,
     #[serde(default)]
     recursive: RecursiveOptions,
 }
 
-#[derive(Debug, Serialize, Deserialize, Default)]
+#[derive(Debug, Deserialize, Default)]
 struct RecursiveOptions {
     ignore: HashSet<String>,
 }
 
 /// A crate source stored inside the .toml
 /// will be translated into on one of the `CrateSource` variants
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Deserialize)]
 struct TomlCrate {
     name: String,
     versions: Option<Vec<String>>,
@@ -67,7 +70,7 @@ struct TomlCrate {
 
 /// Represents an archive we download from crates.io, or a git repo, or a local repo/folder
 /// Once processed (downloaded/extracted/cloned/copied...), this will be translated into a `Crate`
-#[derive(Debug, Serialize, Deserialize, Eq, Hash, PartialEq, Ord, PartialOrd)]
+#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Ord, PartialOrd)]
 enum CrateSource {
     CratesIo {
         name: String,
@@ -111,6 +114,17 @@ struct RustcIce {
     pub crate_name: String,
     pub ice_content: String,
 }
+
+impl Display for RustcIce {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            "{}:\n{}\n========================================\n",
+            self.crate_name, self.ice_content
+        )
+    }
+}
+
 impl RustcIce {
     pub fn from_stderr_and_status(crate_name: &str, status: ExitStatus, stderr: &str) -> Option<Self> {
         if status.code().unwrap_or(0) == 101
@@ -127,60 +141,58 @@ impl RustcIce {
 }
 
 /// A single warning that clippy issued while checking a `Crate`
-#[derive(Debug)]
+#[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 struct ClippyWarning {
-    file: String,
-    line: usize,
-    column: usize,
+    crate_name: String,
+    crate_version: String,
     lint_type: String,
-    message: String,
+    diag: Diagnostic,
 }
 
 #[allow(unused)]
 impl ClippyWarning {
-    fn new(diag: Diagnostic, crate_name: &str, crate_version: &str) -> Option<Self> {
-        let lint_type = diag.code?.code;
+    fn new(mut diag: Diagnostic, crate_name: &str, crate_version: &str) -> Option<Self> {
+        let lint_type = diag.code.clone()?.code;
         if !(lint_type.contains("clippy") || diag.message.contains("clippy"))
             || diag.message.contains("could not read cargo metadata")
         {
             return None;
         }
 
-        let span = diag.spans.into_iter().find(|span| span.is_primary)?;
-
-        let file = if let Ok(stripped) = Path::new(&span.file_name).strip_prefix(env!("CARGO_HOME")) {
-            format!("$CARGO_HOME/{}", stripped.display())
-        } else {
-            format!(
-                "target/lintcheck/sources/{crate_name}-{crate_version}/{}",
-                span.file_name
-            )
-        };
+        // --recursive bypasses cargo so we have to strip the rendered output ourselves
+        let rendered = diag.rendered.as_mut().unwrap();
+        *rendered = strip_ansi_escapes::strip_str(&rendered);
 
         Some(Self {
-            file,
-            line: span.line_start,
-            column: span.column_start,
+            crate_name: crate_name.to_owned(),
+            crate_version: crate_version.to_owned(),
             lint_type,
-            message: diag.message,
+            diag,
         })
     }
 
-    fn to_output(&self, markdown: bool) -> String {
-        let file_with_pos = format!("{}:{}:{}", &self.file, &self.line, &self.column);
-        if markdown {
-            let mut file = self.file.clone();
-            if !file.starts_with('$') {
-                file.insert_str(0, "../");
-            }
+    fn span(&self) -> &DiagnosticSpan {
+        self.diag.spans.iter().find(|span| span.is_primary).unwrap()
+    }
 
-            let mut output = String::from("| ");
-            let _: fmt::Result = write!(output, "[`{file_with_pos}`]({file}#L{})", self.line);
-            let _: fmt::Result = write!(output, r#" | `{:<50}` | "{}" |"#, self.lint_type, self.message);
-            output.push('\n');
-            output
-        } else {
-            format!("{file_with_pos} {} \"{}\"\n", self.lint_type, self.message)
+    fn to_output(&self, format: OutputFormat) -> String {
+        let span = self.span();
+        let mut file = span.file_name.clone();
+        let file_with_pos = format!("{file}:{}:{}", span.line_start, span.line_end);
+        match format {
+            OutputFormat::Text => format!("{file_with_pos} {} \"{}\"\n", self.lint_type, self.diag.message),
+            OutputFormat::Markdown => {
+                if file.starts_with("target") {
+                    file.insert_str(0, "../");
+                }
+
+                let mut output = String::from("| ");
+                write!(output, "[`{file_with_pos}`]({file}#L{})", span.line_start).unwrap();
+                write!(output, r#" | `{:<50}` | "{}" |"#, self.lint_type, self.diag.message).unwrap();
+                output.push('\n');
+                output
+            },
+            OutputFormat::Json => unreachable!("JSON output is handled via serde"),
         }
     }
 }
@@ -333,10 +345,9 @@ impl CrateSource {
 impl Crate {
     /// Run `cargo clippy` on the `Crate` and collect and return all the lint warnings that clippy
     /// issued
-    #[allow(clippy::too_many_arguments)]
+    #[allow(clippy::too_many_arguments, clippy::too_many_lines)]
     fn run_clippy_lints(
         &self,
-        cargo_clippy_path: &Path,
         clippy_driver_path: &Path,
         target_dir_index: &AtomicUsize,
         total_crates_to_lint: usize,
@@ -362,17 +373,27 @@ impl Crate {
             );
         }
 
-        let cargo_clippy_path = fs::canonicalize(cargo_clippy_path).unwrap();
-
         let shared_target_dir = clippy_project_root().join("target/lintcheck/shared_target_dir");
 
-        let mut cargo_clippy_args = if config.fix {
-            vec!["--quiet", "--fix", "--"]
-        } else {
-            vec!["--quiet", "--message-format=json", "--"]
-        };
+        let cargo_home = env!("CARGO_HOME");
+
+        // `src/lib.rs` -> `target/lintcheck/sources/crate-1.2.3/src/lib.rs`
+        let remap_relative = format!("={}", self.path.display());
+        // Fallback for other sources, `~/.cargo/...` -> `$CARGO_HOME/...`
+        let remap_cargo_home = format!("{cargo_home}=$CARGO_HOME");
+        // `~/.cargo/registry/src/index.crates.io-6f17d22bba15001f/crate-2.3.4/src/lib.rs`
+        //     -> `crate-2.3.4/src/lib.rs`
+        let remap_crates_io = format!("{cargo_home}/registry/src/index.crates.io-6f17d22bba15001f/=");
+
+        let mut clippy_args = vec![
+            "--remap-path-prefix",
+            &remap_relative,
+            "--remap-path-prefix",
+            &remap_cargo_home,
+            "--remap-path-prefix",
+            &remap_crates_io,
+        ];
 
-        let mut clippy_args = Vec::<&str>::new();
         if let Some(options) = &self.options {
             for opt in options {
                 clippy_args.push(opt);
@@ -388,23 +409,23 @@ impl Crate {
             clippy_args.extend(lint_filter.iter().map(String::as_str));
         }
 
-        if let Some(server) = server {
-            let target = shared_target_dir.join("recursive");
+        let mut cmd = Command::new("cargo");
+        cmd.arg(if config.fix { "fix" } else { "check" })
+            .arg("--quiet")
+            .current_dir(&self.path)
+            .env("CLIPPY_ARGS", clippy_args.join("__CLIPPY_HACKERY__"));
 
+        if let Some(server) = server {
             // `cargo clippy` is a wrapper around `cargo check` that mainly sets `RUSTC_WORKSPACE_WRAPPER` to
             // `clippy-driver`. We do the same thing here with a couple changes:
             //
             // `RUSTC_WRAPPER` is used instead of `RUSTC_WORKSPACE_WRAPPER` so that we can lint all crate
             // dependencies rather than only workspace members
             //
-            // The wrapper is set to the `lintcheck` so we can force enable linting and ignore certain crates
+            // The wrapper is set to `lintcheck` itself so we can force enable linting and ignore certain crates
             // (see `crate::driver`)
-            let status = Command::new(env::var("CARGO").unwrap_or("cargo".into()))
-                .arg("check")
-                .arg("--quiet")
-                .current_dir(&self.path)
-                .env("CLIPPY_ARGS", clippy_args.join("__CLIPPY_HACKERY__"))
-                .env("CARGO_TARGET_DIR", target)
+            let status = cmd
+                .env("CARGO_TARGET_DIR", shared_target_dir.join("recursive"))
                 .env("RUSTC_WRAPPER", env::current_exe().unwrap())
                 // Pass the absolute path so `crate::driver` can find `clippy-driver`, as it's executed in various
                 // different working directories
@@ -416,23 +437,19 @@ impl Crate {
             assert_eq!(status.code(), Some(0));
 
             return Vec::new();
-        }
+        };
 
-        cargo_clippy_args.extend(clippy_args);
+        if !config.fix {
+            cmd.arg("--message-format=json");
+        }
 
-        let all_output = Command::new(&cargo_clippy_path)
+        let all_output = cmd
             // use the looping index to create individual target dirs
             .env("CARGO_TARGET_DIR", shared_target_dir.join(format!("_{thread_index:?}")))
-            .args(&cargo_clippy_args)
-            .current_dir(&self.path)
+            // Roughly equivalent to `cargo clippy`/`cargo clippy --fix`
+            .env("RUSTC_WORKSPACE_WRAPPER", clippy_driver_path)
             .output()
-            .unwrap_or_else(|error| {
-                panic!(
-                    "Encountered error:\n{error:?}\ncargo_clippy_path: {}\ncrate path:{}\n",
-                    &cargo_clippy_path.display(),
-                    &self.path.display()
-                );
-            });
+            .unwrap();
         let stdout = String::from_utf8_lossy(&all_output.stdout);
         let stderr = String::from_utf8_lossy(&all_output.stderr);
         let status = &all_output.status;
@@ -479,15 +496,17 @@ impl Crate {
 }
 
 /// Builds clippy inside the repo to make sure we have a clippy executable we can use.
-fn build_clippy() {
-    let status = Command::new(env::var("CARGO").unwrap_or("cargo".into()))
-        .arg("build")
-        .status()
-        .expect("Failed to build clippy!");
-    if !status.success() {
+fn build_clippy() -> String {
+    let output = Command::new("cargo")
+        .args(["run", "--bin=clippy-driver", "--", "--version"])
+        .stderr(Stdio::inherit())
+        .output()
+        .unwrap();
+    if !output.status.success() {
         eprintln!("Error: Failed to compile Clippy!");
         std::process::exit(1);
     }
+    String::from_utf8_lossy(&output.stdout).into_owned()
 }
 
 /// Read a `lintcheck_crates.toml` file
@@ -554,10 +573,10 @@ fn read_crates(toml_path: &Path) -> (Vec<CrateSource>, RecursiveOptions) {
 }
 
 /// Generate a short list of occurring lints-types and their count
-fn gather_stats(clippy_warnings: &[ClippyWarning]) -> (String, HashMap<&String, usize>) {
+fn gather_stats(warnings: &[ClippyWarning]) -> (String, HashMap<&String, usize>) {
     // count lint type occurrences
     let mut counter: HashMap<&String, usize> = HashMap::new();
-    clippy_warnings
+    warnings
         .iter()
         .for_each(|wrn| *counter.entry(&wrn.lint_type).or_insert(0) += 1);
 
@@ -580,7 +599,6 @@ fn gather_stats(clippy_warnings: &[ClippyWarning]) -> (String, HashMap<&String,
     (stats_string, counter)
 }
 
-#[allow(clippy::too_many_lines)]
 fn main() {
     // We're being executed as a `RUSTC_WRAPPER` as part of `--recursive`
     if let Ok(addr) = env::var("LINTCHECK_SERVER") {
@@ -595,31 +613,29 @@ fn main() {
 
     let config = LintcheckConfig::new();
 
-    println!("Compiling clippy...");
-    build_clippy();
-    println!("Done compiling");
+    match config.subcommand {
+        Some(Commands::Diff { old, new }) => json::diff(&old, &new),
+        Some(Commands::Popular { output, number }) => popular_crates::fetch(output, number).unwrap(),
+        None => lintcheck(config),
+    }
+}
 
-    let cargo_clippy_path = fs::canonicalize(format!("target/debug/cargo-clippy{EXE_SUFFIX}")).unwrap();
+#[allow(clippy::too_many_lines)]
+fn lintcheck(config: LintcheckConfig) {
+    let clippy_ver = build_clippy();
     let clippy_driver_path = fs::canonicalize(format!("target/debug/clippy-driver{EXE_SUFFIX}")).unwrap();
 
     // assert that clippy is found
     assert!(
-        cargo_clippy_path.is_file(),
-        "target/debug/cargo-clippy binary not found! {}",
-        cargo_clippy_path.display()
+        clippy_driver_path.is_file(),
+        "target/debug/clippy-driver binary not found! {}",
+        clippy_driver_path.display()
     );
 
-    let clippy_ver = Command::new(&cargo_clippy_path)
-        .arg("--version")
-        .output()
-        .map(|o| String::from_utf8_lossy(&o.stdout).into_owned())
-        .expect("could not get clippy version!");
-
     // download and extract the crates, then run clippy on them and collect clippy's warnings
     // flatten into one big list of warnings
 
     let (crates, recursive_options) = read_crates(&config.sources_toml_path);
-    let old_stats = read_stats_from_file(&config.lintcheck_results_path);
 
     let counter = AtomicUsize::new(1);
     let lint_filter: Vec<String> = config
@@ -678,7 +694,6 @@ fn main() {
         .par_iter()
         .flat_map(|krate| {
             krate.run_clippy_lints(
-                &cargo_clippy_path,
                 &clippy_driver_path,
                 &counter,
                 crates.len(),
@@ -711,39 +726,51 @@ fn main() {
         }
     }
 
+    let text = match config.format {
+        OutputFormat::Text | OutputFormat::Markdown => output(&warnings, &raw_ices, clippy_ver, &config),
+        OutputFormat::Json => {
+            if !raw_ices.is_empty() {
+                for ice in raw_ices {
+                    println!("{ice}");
+                }
+                panic!("Some crates ICEd");
+            }
+
+            json::output(&warnings)
+        },
+    };
+
+    println!("Writing logs to {}", config.lintcheck_results_path.display());
+    fs::create_dir_all(config.lintcheck_results_path.parent().unwrap()).unwrap();
+    fs::write(&config.lintcheck_results_path, text).unwrap();
+}
+
+/// Creates the log file output for [`OutputFormat::Text`] and [`OutputFormat::Markdown`]
+fn output(warnings: &[ClippyWarning], ices: &[RustcIce], clippy_ver: String, config: &LintcheckConfig) -> String {
     // generate some stats
-    let (stats_formatted, new_stats) = gather_stats(&warnings);
+    let (stats_formatted, new_stats) = gather_stats(warnings);
+    let old_stats = read_stats_from_file(&config.lintcheck_results_path);
 
-    let mut all_msgs: Vec<String> = warnings.iter().map(|warn| warn.to_output(config.markdown)).collect();
+    let mut all_msgs: Vec<String> = warnings.iter().map(|warn| warn.to_output(config.format)).collect();
     all_msgs.sort();
     all_msgs.push("\n\n### Stats:\n\n".into());
     all_msgs.push(stats_formatted);
 
-    // save the text into lintcheck-logs/logs.txt
     let mut text = clippy_ver; // clippy version number on top
     text.push_str("\n### Reports\n\n");
-    if config.markdown {
+    if config.format == OutputFormat::Markdown {
         text.push_str("| file | lint | message |\n");
         text.push_str("| --- | --- | --- |\n");
     }
     write!(text, "{}", all_msgs.join("")).unwrap();
     text.push_str("\n\n### ICEs:\n");
-    for ice in &raw_ices {
-        let _: fmt::Result = write!(
-            text,
-            "{}:\n{}\n========================================\n\n",
-            ice.crate_name, ice.ice_content
-        );
+    for ice in ices {
+        writeln!(text, "{ice}").unwrap();
     }
 
-    println!("Writing logs to {}", config.lintcheck_results_path.display());
-    if !raw_ices.is_empty() {
-        println!("WARNING: at least one ICE reported, check log file");
-    }
-    fs::create_dir_all(config.lintcheck_results_path.parent().unwrap()).unwrap();
-    fs::write(&config.lintcheck_results_path, text).unwrap();
-
     print_stats(old_stats, new_stats, &config.lint_filter);
+
+    text
 }
 
 /// read the previous stats from the lintcheck-log file
@@ -865,7 +892,7 @@ fn lintcheck_test() {
         "--crates-toml",
         "lintcheck/test_sources.toml",
     ];
-    let status = Command::new(env::var("CARGO").unwrap_or("cargo".into()))
+    let status = Command::new("cargo")
         .args(args)
         .current_dir("..") // repo root
         .status();
diff --git a/src/tools/clippy/lintcheck/src/popular-crates.rs b/src/tools/clippy/lintcheck/src/popular-crates.rs
deleted file mode 100644
index fdab984ad86..00000000000
--- a/src/tools/clippy/lintcheck/src/popular-crates.rs
+++ /dev/null
@@ -1,65 +0,0 @@
-#![deny(clippy::pedantic)]
-
-use clap::Parser;
-use crates_io_api::{CratesQueryBuilder, Sort, SyncClient};
-use indicatif::ProgressBar;
-use std::collections::HashSet;
-use std::fs::File;
-use std::io::{BufWriter, Write};
-use std::path::PathBuf;
-use std::time::Duration;
-
-#[derive(Parser)]
-struct Opts {
-    /// Output TOML file name
-    output: PathBuf,
-    /// Number of crate names to download
-    #[clap(short, long, default_value_t = 100)]
-    number: usize,
-    /// Do not output progress
-    #[clap(short, long)]
-    quiet: bool,
-}
-
-fn main() -> anyhow::Result<()> {
-    let opts = Opts::parse();
-    let mut output = BufWriter::new(File::create(opts.output)?);
-    output.write_all(b"[crates]\n")?;
-    let client = SyncClient::new(
-        "clippy/lintcheck (github.com/rust-lang/rust-clippy/)",
-        Duration::from_secs(1),
-    )?;
-    let mut seen_crates = HashSet::new();
-    let pb = if opts.quiet {
-        None
-    } else {
-        Some(ProgressBar::new(opts.number as u64))
-    };
-    let mut query = CratesQueryBuilder::new()
-        .sort(Sort::RecentDownloads)
-        .page_size(100)
-        .build();
-    while seen_crates.len() < opts.number {
-        let retrieved = client.crates(query.clone())?.crates;
-        if retrieved.is_empty() {
-            eprintln!("No more than {} crates available from API", seen_crates.len());
-            break;
-        }
-        for c in retrieved {
-            if seen_crates.insert(c.name.clone()) {
-                output.write_all(
-                    format!(
-                        "{} = {{ name = '{}', versions = ['{}'] }}\n",
-                        c.name, c.name, c.max_version
-                    )
-                    .as_bytes(),
-                )?;
-                if let Some(pb) = &pb {
-                    pb.inc(1);
-                }
-            }
-        }
-        query.set_page(query.page() + 1);
-    }
-    Ok(())
-}
diff --git a/src/tools/clippy/lintcheck/src/popular_crates.rs b/src/tools/clippy/lintcheck/src/popular_crates.rs
new file mode 100644
index 00000000000..880a8bd81f0
--- /dev/null
+++ b/src/tools/clippy/lintcheck/src/popular_crates.rs
@@ -0,0 +1,52 @@
+use serde::Deserialize;
+use std::error::Error;
+use std::fmt::Write;
+use std::fs;
+use std::path::PathBuf;
+
+#[derive(Deserialize, Debug)]
+struct Page {
+    crates: Vec<Crate>,
+    meta: Meta,
+}
+
+#[derive(Deserialize, Debug)]
+struct Crate {
+    name: String,
+    max_version: String,
+}
+
+#[derive(Deserialize, Debug)]
+struct Meta {
+    next_page: String,
+}
+
+pub(crate) fn fetch(output: PathBuf, number: usize) -> Result<(), Box<dyn Error>> {
+    let agent = ureq::builder()
+        .user_agent("clippy/lintcheck (github.com/rust-lang/rust-clippy/)")
+        .build();
+
+    let mut crates = Vec::with_capacity(number);
+    let mut query = "?sort=recent-downloads&per_page=100".to_string();
+    while crates.len() < number {
+        let page: Page = agent
+            .get(&format!("https://crates.io/api/v1/crates{query}"))
+            .call()?
+            .into_json()?;
+
+        query = page.meta.next_page;
+        crates.extend(page.crates);
+        crates.truncate(number);
+
+        let width = number.ilog10() as usize + 1;
+        println!("Fetched {:>width$}/{number} crates", crates.len());
+    }
+
+    let mut out = "[crates]\n".to_string();
+    for Crate { name, max_version } in crates {
+        writeln!(out, "{name} = {{ name = '{name}', versions = ['{max_version}'] }}").unwrap();
+    }
+    fs::write(output, out)?;
+
+    Ok(())
+}
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index 842c2f3de0d..72b50d59f7e 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2024-06-13"
+channel = "nightly-2024-06-27"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index 6117e76897f..9b1577f24b8 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -2,7 +2,7 @@
 #![allow(rustc::untranslatable_diagnostic)]
 #![feature(rustc_private)]
 #![feature(let_chains)]
-#![feature(lint_reasons)]
+#![cfg_attr(bootstrap, feature(lint_reasons))]
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
 // warn on lints, that are included in `rust-lang/rust`s bootstrap
 #![warn(rust_2018_idioms, unused_lifetimes)]
diff --git a/src/tools/clippy/tests/integration.rs b/src/tools/clippy/tests/integration.rs
index 7f4500826ff..19c5f3a4133 100644
--- a/src/tools/clippy/tests/integration.rs
+++ b/src/tools/clippy/tests/integration.rs
@@ -55,6 +55,7 @@ fn integration_test() {
             "clippy",
             "--all-targets",
             "--all-features",
+            "--message-format=short",
             "--",
             "--cap-lints",
             "warn",
diff --git a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/Cargo.stderr
index 912ea9bb4d1..b626551e35b 100644
--- a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/Cargo.stderr
+++ b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/Cargo.stderr
@@ -1,10 +1,10 @@
 error: file is loaded as a module multiple times: `src/b.rs`
- --> src/main.rs:5:1
+ --> src/main.rs:3:1
   |
-5 |   mod b;
+3 |   mod b;
   |   ^^^^^^ first loaded here
-6 | / #[path = "b.rs"]
-7 | | mod b2;
+4 | / #[path = "b.rs"]
+5 | | mod b2;
   | |_______^ loaded again here
   |
   = help: replace all but one `mod` item with `use` items
@@ -12,34 +12,34 @@ error: file is loaded as a module multiple times: `src/b.rs`
   = help: to override `-D warnings` add `#[allow(clippy::duplicate_mod)]`
 
 error: file is loaded as a module multiple times: `src/c.rs`
-  --> src/main.rs:9:1
+  --> src/main.rs:7:1
    |
-9  |   mod c;
+7  |   mod c;
    |   ^^^^^^ first loaded here
-10 | / #[path = "c.rs"]
-11 | | mod c2;
+8  | / #[path = "c.rs"]
+9  | | mod c2;
    | |_______^ loaded again here
-12 | / #[path = "c.rs"]
-13 | | mod c3;
+10 | / #[path = "c.rs"]
+11 | | mod c3;
    | |_______^ loaded again here
    |
    = help: replace all but one `mod` item with `use` items
 
 error: file is loaded as a module multiple times: `src/d.rs`
-  --> src/main.rs:18:1
+  --> src/main.rs:16:1
    |
-18 |   mod d;
+16 |   mod d;
    |   ^^^^^^ first loaded here
-19 | / #[path = "d.rs"]
-20 | | mod d2;
+17 | / #[path = "d.rs"]
+18 | | mod d2;
    | |_______^ loaded again here
    |
    = help: replace all but one `mod` item with `use` items
 
 error: file is loaded as a module multiple times: `src/from_other_module.rs`
-  --> src/main.rs:15:1
+  --> src/main.rs:13:1
    |
-15 |   mod from_other_module;
+13 |   mod from_other_module;
    |   ^^^^^^^^^^^^^^^^^^^^^^ first loaded here
    |
   ::: src/other_module/mod.rs:1:1
diff --git a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.rs b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.rs
index 6478e65ac81..9cbe4b83b25 100644
--- a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.rs
@@ -1,5 +1,3 @@
-#![feature(lint_reasons)]
-
 mod a;
 
 mod b;
diff --git a/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs
index f5e01b431ad..a312df5a43a 100644
--- a/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs
+++ b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs
@@ -1,5 +1,5 @@
 //! Tests macro_metavars_in_unsafe with default configuration
-#![feature(decl_macro, lint_reasons)]
+#![feature(decl_macro)]
 #![warn(clippy::macro_metavars_in_unsafe)]
 #![allow(clippy::no_effect)]
 
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 63fdea710cb..17fceae0178 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
@@ -40,6 +40,7 @@ fn main() {
 
     a.sort_unstable();
 
+    // FIXME(f16_f128): add a clamp test once the function is available
     let _ = 2.0f32.clamp(3.0f32, 4.0f32);
     let _ = 2.0f64.clamp(3.0f64, 4.0f64);
 
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 55e867d5f39..4afbbf5f807 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
@@ -28,61 +28,61 @@ LL |     a.sort_unstable();
    |     ^^^^^^^^^^^^^^^^^
 
 error: use of a disallowed method `f32::clamp`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:43:13
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:44:13
    |
 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:46:61
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:47: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:49:28
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:50: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:50:53
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:51: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:53:31
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:54: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:55:5
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:56: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:56:5
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:57: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:58:5
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:59:5
    |
 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:59:5
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:60:5
    |
 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:60:5
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:61:5
    |
 LL |     s.implemented_method();
    |     ^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.default.stderr b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.default.stderr
index 37d69055737..a44c810b135 100644
--- a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.default.stderr
+++ b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.default.stderr
@@ -1,5 +1,5 @@
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:271:19
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:270:19
    |
 LL |     /* Safety: */ unsafe {}
    |                   ^^^^^^^^^
@@ -9,7 +9,7 @@ LL |     /* Safety: */ unsafe {}
    = help: to override `-D warnings` add `#[allow(clippy::undocumented_unsafe_blocks)]`
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:275:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:274:5
    |
 LL |     unsafe {}
    |     ^^^^^^^^^
@@ -17,7 +17,7 @@ LL |     unsafe {}
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:279:14
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:278:14
    |
 LL |     let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
    |              ^^^^^^^^^^^^^
@@ -25,7 +25,7 @@ LL |     let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:279:29
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:278:29
    |
 LL |     let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
    |                             ^^^^^^^^^^^^^
@@ -33,7 +33,7 @@ LL |     let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:279:48
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:278:48
    |
 LL |     let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
    |                                                ^^^^^^^^^^^^^
@@ -41,7 +41,7 @@ LL |     let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:283:18
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:282:18
    |
 LL |     let _ = (42, unsafe {}, "test", unsafe {});
    |                  ^^^^^^^^^
@@ -49,7 +49,7 @@ LL |     let _ = (42, unsafe {}, "test", unsafe {});
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:283:37
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:282:37
    |
 LL |     let _ = (42, unsafe {}, "test", unsafe {});
    |                                     ^^^^^^^^^
@@ -57,7 +57,7 @@ LL |     let _ = (42, unsafe {}, "test", unsafe {});
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:287:14
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:286:14
    |
 LL |     let _ = *unsafe { &42 };
    |              ^^^^^^^^^^^^^^
@@ -65,7 +65,7 @@ LL |     let _ = *unsafe { &42 };
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:292:19
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:291:19
    |
 LL |     let _ = match unsafe {} {
    |                   ^^^^^^^^^
@@ -73,7 +73,7 @@ LL |     let _ = match unsafe {} {
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:298:14
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:297:14
    |
 LL |     let _ = &unsafe {};
    |              ^^^^^^^^^
@@ -81,7 +81,7 @@ LL |     let _ = &unsafe {};
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:302:14
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:301:14
    |
 LL |     let _ = [unsafe {}; 5];
    |              ^^^^^^^^^
@@ -89,7 +89,7 @@ LL |     let _ = [unsafe {}; 5];
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:306:13
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:305:13
    |
 LL |     let _ = unsafe {};
    |             ^^^^^^^^^
@@ -97,7 +97,7 @@ LL |     let _ = unsafe {};
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:316:8
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:315:8
    |
 LL |     t!(unsafe {});
    |        ^^^^^^^^^
@@ -105,7 +105,7 @@ LL |     t!(unsafe {});
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:322:13
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:321:13
    |
 LL |             unsafe {}
    |             ^^^^^^^^^
@@ -117,7 +117,7 @@ LL |     t!();
    = note: this error originates in the macro `t` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:330:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:329:5
    |
 LL |     unsafe {} // SAFETY:
    |     ^^^^^^^^^
@@ -125,7 +125,7 @@ LL |     unsafe {} // SAFETY:
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:334:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:333:5
    |
 LL |     unsafe {
    |     ^^^^^^^^
@@ -133,7 +133,7 @@ LL |     unsafe {
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:344:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:343:5
    |
 LL |     unsafe {};
    |     ^^^^^^^^^
@@ -141,7 +141,7 @@ LL |     unsafe {};
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:348:20
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:347:20
    |
 LL |     println!("{}", unsafe { String::from_utf8_unchecked(vec![]) });
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -149,7 +149,7 @@ LL |     println!("{}", unsafe { String::from_utf8_unchecked(vec![]) });
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe impl missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:355:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:354:5
    |
 LL |     unsafe impl A for () {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^
@@ -157,7 +157,7 @@ LL |     unsafe impl A for () {}
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe impl missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:362:9
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:361:9
    |
 LL |         unsafe impl B for (u32) {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -165,7 +165,7 @@ LL |         unsafe impl B for (u32) {}
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe impl missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:383:13
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:382:13
    |
 LL |             unsafe impl T for $t {}
    |             ^^^^^^^^^^^^^^^^^^^^^^^
@@ -177,7 +177,7 @@ LL |     no_safety_comment!(());
    = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: unsafe impl missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:408:13
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:407:13
    |
 LL |             unsafe impl T for $t {}
    |             ^^^^^^^^^^^^^^^^^^^^^^^
@@ -189,7 +189,7 @@ LL |     no_safety_comment!(());
    = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: unsafe impl missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:416:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:415:5
    |
 LL |     unsafe impl T for (i32) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -197,7 +197,7 @@ LL |     unsafe impl T for (i32) {}
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe impl missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:408:13
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:407:13
    |
 LL |             unsafe impl T for $t {}
    |             ^^^^^^^^^^^^^^^^^^^^^^^
@@ -209,7 +209,7 @@ LL |     no_safety_comment!(u32);
    = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: unsafe impl missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:422:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:421:5
    |
 LL |     unsafe impl T for (bool) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -217,7 +217,7 @@ LL |     unsafe impl T for (bool) {}
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe impl missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:468:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:467:5
    |
 LL |     unsafe impl NoComment for () {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -225,7 +225,7 @@ LL |     unsafe impl NoComment for () {}
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe impl missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:472:19
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:471:19
    |
 LL |     /* SAFETY: */ unsafe impl InlineComment for () {}
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -233,7 +233,7 @@ LL |     /* SAFETY: */ unsafe impl InlineComment for () {}
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe impl missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:476:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:475:5
    |
 LL |     unsafe impl TrailingComment for () {} // SAFETY:
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -241,13 +241,13 @@ LL |     unsafe impl TrailingComment for () {} // SAFETY:
    = help: consider adding a safety comment on the preceding line
 
 error: constant item has unnecessary safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:480:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:479:5
    |
 LL |     const BIG_NUMBER: i32 = 1000000;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: consider removing the safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:479:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:478:5
    |
 LL |     // SAFETY:
    |     ^^^^^^^^^^
@@ -255,7 +255,7 @@ LL |     // SAFETY:
    = help: to override `-D warnings` add `#[allow(clippy::unnecessary_safety_comment)]`
 
 error: unsafe impl missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:481:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:480:5
    |
 LL |     unsafe impl Interference for () {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -263,7 +263,7 @@ LL |     unsafe impl Interference for () {}
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe impl missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:488:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:487:5
    |
 LL |     unsafe impl ImplInFn for () {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -271,7 +271,7 @@ LL |     unsafe impl ImplInFn for () {}
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe impl missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:497:1
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:496:1
    |
 LL | unsafe impl CrateRoot for () {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -279,7 +279,7 @@ LL | unsafe impl CrateRoot for () {}
    = help: consider adding a safety comment on the preceding line
 
 error: statement has unnecessary safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:510:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:509:5
    |
 LL | /     let _ = {
 LL | |         if unsafe { true } {
@@ -291,13 +291,13 @@ LL | |     };
    | |______^
    |
 help: consider removing the safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:509:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:508:5
    |
 LL |     // SAFETY: this is more than one level away, so it should warn
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:511:12
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:510:12
    |
 LL |         if unsafe { true } {
    |            ^^^^^^^^^^^^^^^
@@ -305,7 +305,7 @@ LL |         if unsafe { true } {
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:514:23
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:513:23
    |
 LL |             let bar = unsafe {};
    |                       ^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr
index 400fde997e9..db5ea5b6289 100644
--- a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr
+++ b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr
@@ -1,5 +1,5 @@
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:271:19
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:270:19
    |
 LL |     /* Safety: */ unsafe {}
    |                   ^^^^^^^^^
@@ -9,7 +9,7 @@ LL |     /* Safety: */ unsafe {}
    = help: to override `-D warnings` add `#[allow(clippy::undocumented_unsafe_blocks)]`
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:275:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:274:5
    |
 LL |     unsafe {}
    |     ^^^^^^^^^
@@ -17,7 +17,7 @@ LL |     unsafe {}
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:279:14
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:278:14
    |
 LL |     let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
    |              ^^^^^^^^^^^^^
@@ -25,7 +25,7 @@ LL |     let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:279:29
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:278:29
    |
 LL |     let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
    |                             ^^^^^^^^^^^^^
@@ -33,7 +33,7 @@ LL |     let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:279:48
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:278:48
    |
 LL |     let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
    |                                                ^^^^^^^^^^^^^
@@ -41,7 +41,7 @@ LL |     let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:283:18
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:282:18
    |
 LL |     let _ = (42, unsafe {}, "test", unsafe {});
    |                  ^^^^^^^^^
@@ -49,7 +49,7 @@ LL |     let _ = (42, unsafe {}, "test", unsafe {});
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:283:37
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:282:37
    |
 LL |     let _ = (42, unsafe {}, "test", unsafe {});
    |                                     ^^^^^^^^^
@@ -57,7 +57,7 @@ LL |     let _ = (42, unsafe {}, "test", unsafe {});
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:287:14
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:286:14
    |
 LL |     let _ = *unsafe { &42 };
    |              ^^^^^^^^^^^^^^
@@ -65,7 +65,7 @@ LL |     let _ = *unsafe { &42 };
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:292:19
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:291:19
    |
 LL |     let _ = match unsafe {} {
    |                   ^^^^^^^^^
@@ -73,7 +73,7 @@ LL |     let _ = match unsafe {} {
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:298:14
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:297:14
    |
 LL |     let _ = &unsafe {};
    |              ^^^^^^^^^
@@ -81,7 +81,7 @@ LL |     let _ = &unsafe {};
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:302:14
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:301:14
    |
 LL |     let _ = [unsafe {}; 5];
    |              ^^^^^^^^^
@@ -89,7 +89,7 @@ LL |     let _ = [unsafe {}; 5];
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:306:13
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:305:13
    |
 LL |     let _ = unsafe {};
    |             ^^^^^^^^^
@@ -97,7 +97,7 @@ LL |     let _ = unsafe {};
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:316:8
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:315:8
    |
 LL |     t!(unsafe {});
    |        ^^^^^^^^^
@@ -105,7 +105,7 @@ LL |     t!(unsafe {});
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:322:13
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:321:13
    |
 LL |             unsafe {}
    |             ^^^^^^^^^
@@ -117,7 +117,7 @@ LL |     t!();
    = note: this error originates in the macro `t` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:330:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:329:5
    |
 LL |     unsafe {} // SAFETY:
    |     ^^^^^^^^^
@@ -125,7 +125,7 @@ LL |     unsafe {} // SAFETY:
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:334:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:333:5
    |
 LL |     unsafe {
    |     ^^^^^^^^
@@ -133,7 +133,7 @@ LL |     unsafe {
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:344:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:343:5
    |
 LL |     unsafe {};
    |     ^^^^^^^^^
@@ -141,7 +141,7 @@ LL |     unsafe {};
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:348:20
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:347:20
    |
 LL |     println!("{}", unsafe { String::from_utf8_unchecked(vec![]) });
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -149,7 +149,7 @@ LL |     println!("{}", unsafe { String::from_utf8_unchecked(vec![]) });
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe impl missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:355:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:354:5
    |
 LL |     unsafe impl A for () {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^
@@ -157,7 +157,7 @@ LL |     unsafe impl A for () {}
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe impl missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:362:9
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:361:9
    |
 LL |         unsafe impl B for (u32) {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -165,7 +165,7 @@ LL |         unsafe impl B for (u32) {}
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe impl missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:383:13
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:382:13
    |
 LL |             unsafe impl T for $t {}
    |             ^^^^^^^^^^^^^^^^^^^^^^^
@@ -177,7 +177,7 @@ LL |     no_safety_comment!(());
    = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: unsafe impl missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:408:13
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:407:13
    |
 LL |             unsafe impl T for $t {}
    |             ^^^^^^^^^^^^^^^^^^^^^^^
@@ -189,7 +189,7 @@ LL |     no_safety_comment!(());
    = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: unsafe impl missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:416:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:415:5
    |
 LL |     unsafe impl T for (i32) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -197,7 +197,7 @@ LL |     unsafe impl T for (i32) {}
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe impl missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:408:13
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:407:13
    |
 LL |             unsafe impl T for $t {}
    |             ^^^^^^^^^^^^^^^^^^^^^^^
@@ -209,7 +209,7 @@ LL |     no_safety_comment!(u32);
    = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: unsafe impl missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:422:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:421:5
    |
 LL |     unsafe impl T for (bool) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -217,7 +217,7 @@ LL |     unsafe impl T for (bool) {}
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe impl missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:468:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:467:5
    |
 LL |     unsafe impl NoComment for () {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -225,7 +225,7 @@ LL |     unsafe impl NoComment for () {}
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe impl missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:472:19
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:471:19
    |
 LL |     /* SAFETY: */ unsafe impl InlineComment for () {}
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -233,7 +233,7 @@ LL |     /* SAFETY: */ unsafe impl InlineComment for () {}
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe impl missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:476:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:475:5
    |
 LL |     unsafe impl TrailingComment for () {} // SAFETY:
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -241,13 +241,13 @@ LL |     unsafe impl TrailingComment for () {} // SAFETY:
    = help: consider adding a safety comment on the preceding line
 
 error: constant item has unnecessary safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:480:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:479:5
    |
 LL |     const BIG_NUMBER: i32 = 1000000;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: consider removing the safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:479:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:478:5
    |
 LL |     // SAFETY:
    |     ^^^^^^^^^^
@@ -255,7 +255,7 @@ LL |     // SAFETY:
    = help: to override `-D warnings` add `#[allow(clippy::unnecessary_safety_comment)]`
 
 error: unsafe impl missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:481:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:480:5
    |
 LL |     unsafe impl Interference for () {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -263,7 +263,7 @@ LL |     unsafe impl Interference for () {}
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe impl missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:488:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:487:5
    |
 LL |     unsafe impl ImplInFn for () {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -271,7 +271,7 @@ LL |     unsafe impl ImplInFn for () {}
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe impl missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:497:1
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:496:1
    |
 LL | unsafe impl CrateRoot for () {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -279,7 +279,7 @@ LL | unsafe impl CrateRoot for () {}
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:507:9
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:506:9
    |
 LL |         unsafe {};
    |         ^^^^^^^^^
@@ -287,7 +287,7 @@ LL |         unsafe {};
    = help: consider adding a safety comment on the preceding line
 
 error: statement has unnecessary safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:510:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:509:5
    |
 LL | /     let _ = {
 LL | |         if unsafe { true } {
@@ -299,13 +299,13 @@ LL | |     };
    | |______^
    |
 help: consider removing the safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:509:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:508:5
    |
 LL |     // SAFETY: this is more than one level away, so it should warn
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:511:12
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:510:12
    |
 LL |         if unsafe { true } {
    |            ^^^^^^^^^^^^^^^
@@ -313,7 +313,7 @@ LL |         if unsafe { true } {
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:514:23
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:513:23
    |
 LL |             let bar = unsafe {};
    |                       ^^^^^^^^^
@@ -321,7 +321,7 @@ LL |             let bar = unsafe {};
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:532:9
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:531:9
    |
 LL |         unsafe { a_function_with_a_very_long_name_to_break_the_line() };
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -329,7 +329,7 @@ LL |         unsafe { a_function_with_a_very_long_name_to_break_the_line() };
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:536:9
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:535:9
    |
 LL |         unsafe { a_const_function_with_a_very_long_name_to_break_the_line() };
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -337,7 +337,7 @@ LL |         unsafe { a_const_function_with_a_very_long_name_to_break_the_line()
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:540:9
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:539:9
    |
 LL |         unsafe { a_const_function_with_a_very_long_name_to_break_the_line() };
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -345,7 +345,7 @@ LL |         unsafe { a_const_function_with_a_very_long_name_to_break_the_line()
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:546:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:545:5
    |
 LL |     unsafe {}
    |     ^^^^^^^^^
@@ -353,7 +353,7 @@ LL |     unsafe {}
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:550:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:549:5
    |
 LL |     unsafe {
    |     ^^^^^^^^
@@ -361,7 +361,7 @@ LL |     unsafe {
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:557:9
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:556:9
    |
 LL |         unsafe { a_function_with_a_very_long_name_to_break_the_line() };
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -369,7 +369,7 @@ LL |         unsafe { a_function_with_a_very_long_name_to_break_the_line() };
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:562:9
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:561:9
    |
 LL |         unsafe { a_const_function_with_a_very_long_name_to_break_the_line() };
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -377,7 +377,7 @@ LL |         unsafe { a_const_function_with_a_very_long_name_to_break_the_line()
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:568:9
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:567:9
    |
 LL |         unsafe { a_const_function_with_a_very_long_name_to_break_the_line() };
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -385,7 +385,7 @@ LL |         unsafe { a_const_function_with_a_very_long_name_to_break_the_line()
    = help: consider adding a safety comment on the preceding line
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:573:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:572:5
    |
 LL |     unsafe {}
    |     ^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs
index e5ef9d35fb6..02170e1f740 100644
--- a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs
@@ -10,7 +10,6 @@
     clippy::let_unit_value,
     clippy::missing_safety_doc
 )]
-#![feature(lint_reasons)]
 
 extern crate proc_macro_unsafe;
 
diff --git a/src/tools/clippy/tests/ui/allow_attributes.fixed b/src/tools/clippy/tests/ui/allow_attributes.fixed
index b506a9890f5..49ee3ee17c7 100644
--- a/src/tools/clippy/tests/ui/allow_attributes.fixed
+++ b/src/tools/clippy/tests/ui/allow_attributes.fixed
@@ -1,7 +1,6 @@
 //@aux-build:proc_macros.rs
 #![allow(unused)]
 #![warn(clippy::allow_attributes)]
-#![feature(lint_reasons)]
 #![no_main]
 
 extern crate proc_macros;
@@ -47,3 +46,15 @@ fn ignore_proc_macro() {
 fn ignore_inner_attr() {
     #![allow(unused)] // Should not lint
 }
+
+#[clippy::msrv = "1.81"]
+fn msrv_1_81() {
+    #[expect(unused)]
+    let x = 1;
+}
+
+#[clippy::msrv = "1.80"]
+fn msrv_1_80() {
+    #[allow(unused)]
+    let x = 1;
+}
diff --git a/src/tools/clippy/tests/ui/allow_attributes.rs b/src/tools/clippy/tests/ui/allow_attributes.rs
index c7daa7abd9d..854acf8348d 100644
--- a/src/tools/clippy/tests/ui/allow_attributes.rs
+++ b/src/tools/clippy/tests/ui/allow_attributes.rs
@@ -1,7 +1,6 @@
 //@aux-build:proc_macros.rs
 #![allow(unused)]
 #![warn(clippy::allow_attributes)]
-#![feature(lint_reasons)]
 #![no_main]
 
 extern crate proc_macros;
@@ -47,3 +46,15 @@ fn ignore_proc_macro() {
 fn ignore_inner_attr() {
     #![allow(unused)] // Should not lint
 }
+
+#[clippy::msrv = "1.81"]
+fn msrv_1_81() {
+    #[allow(unused)]
+    let x = 1;
+}
+
+#[clippy::msrv = "1.80"]
+fn msrv_1_80() {
+    #[allow(unused)]
+    let x = 1;
+}
diff --git a/src/tools/clippy/tests/ui/allow_attributes.stderr b/src/tools/clippy/tests/ui/allow_attributes.stderr
index 9c99e88c796..10dac0bc808 100644
--- a/src/tools/clippy/tests/ui/allow_attributes.stderr
+++ b/src/tools/clippy/tests/ui/allow_attributes.stderr
@@ -1,5 +1,5 @@
 error: #[allow] attribute found
-  --> tests/ui/allow_attributes.rs:13:3
+  --> tests/ui/allow_attributes.rs:12:3
    |
 LL | #[allow(dead_code)]
    |   ^^^^^ help: replace it with: `expect`
@@ -8,10 +8,24 @@ LL | #[allow(dead_code)]
    = help: to override `-D warnings` add `#[allow(clippy::allow_attributes)]`
 
 error: #[allow] attribute found
-  --> tests/ui/allow_attributes.rs:22:30
+  --> tests/ui/allow_attributes.rs:21:30
    |
 LL | #[cfg_attr(panic = "unwind", allow(dead_code))]
    |                              ^^^^^ help: replace it with: `expect`
 
-error: aborting due to 2 previous errors
+error: #[allow] attribute found
+  --> tests/ui/allow_attributes.rs:52:7
+   |
+LL |     #[allow(unused)]
+   |       ^^^^^ help: replace it with: `expect`
+
+error: #[allow] attribute found
+  --> tests/ui/allow_attributes.rs:52:7
+   |
+LL |     #[allow(unused)]
+   |       ^^^^^ help: replace it with: `expect`
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/allow_attributes_without_reason.rs b/src/tools/clippy/tests/ui/allow_attributes_without_reason.rs
index 523148d6586..86f6b2c5742 100644
--- a/src/tools/clippy/tests/ui/allow_attributes_without_reason.rs
+++ b/src/tools/clippy/tests/ui/allow_attributes_without_reason.rs
@@ -1,5 +1,4 @@
 //@aux-build:proc_macros.rs
-#![feature(lint_reasons)]
 #![deny(clippy::allow_attributes_without_reason)]
 #![allow(unfulfilled_lint_expectations, clippy::duplicated_attributes)]
 
@@ -42,3 +41,15 @@ pub fn trigger_fp_result() -> Result<(), &'static str> {
     Err("asdf")?;
     Ok(())
 }
+
+#[clippy::msrv = "1.81"]
+fn msrv_1_81() {
+    #[allow(unused)]
+    let _ = 1;
+}
+
+#[clippy::msrv = "1.80"]
+fn msrv_1_80() {
+    #[allow(unused)]
+    let _ = 1;
+}
diff --git a/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr b/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr
index 770a771ec3d..9bc3ca0f2af 100644
--- a/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr
+++ b/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr
@@ -1,18 +1,18 @@
 error: `allow` attribute without specifying a reason
-  --> tests/ui/allow_attributes_without_reason.rs:4:1
+  --> tests/ui/allow_attributes_without_reason.rs:3:1
    |
 LL | #![allow(unfulfilled_lint_expectations, clippy::duplicated_attributes)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: try adding a reason at the end with `, reason = ".."`
 note: the lint level is defined here
-  --> tests/ui/allow_attributes_without_reason.rs:3:9
+  --> tests/ui/allow_attributes_without_reason.rs:2:9
    |
 LL | #![deny(clippy::allow_attributes_without_reason)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `allow` attribute without specifying a reason
-  --> tests/ui/allow_attributes_without_reason.rs:10:1
+  --> tests/ui/allow_attributes_without_reason.rs:9:1
    |
 LL | #[allow(dead_code)]
    | ^^^^^^^^^^^^^^^^^^^
@@ -20,7 +20,7 @@ LL | #[allow(dead_code)]
    = help: try adding a reason at the end with `, reason = ".."`
 
 error: `allow` attribute without specifying a reason
-  --> tests/ui/allow_attributes_without_reason.rs:11:1
+  --> tests/ui/allow_attributes_without_reason.rs:10:1
    |
 LL | #[allow(dead_code, deprecated)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -28,12 +28,29 @@ LL | #[allow(dead_code, deprecated)]
    = help: try adding a reason at the end with `, reason = ".."`
 
 error: `expect` attribute without specifying a reason
-  --> tests/ui/allow_attributes_without_reason.rs:12:1
+  --> tests/ui/allow_attributes_without_reason.rs:11:1
    |
 LL | #[expect(dead_code)]
    | ^^^^^^^^^^^^^^^^^^^^
    |
    = help: try adding a reason at the end with `, reason = ".."`
 
-error: aborting due to 4 previous errors
+error: `allow` attribute without specifying a reason
+  --> tests/ui/allow_attributes_without_reason.rs:47:5
+   |
+LL |     #[allow(unused)]
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = help: try adding a reason at the end with `, reason = ".."`
+
+error: `allow` attribute without specifying a reason
+  --> tests/ui/allow_attributes_without_reason.rs:47:5
+   |
+LL |     #[allow(unused)]
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = help: try adding a reason at the end with `, reason = ".."`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
index 33a91e8bbbe..9d06e14e88c 100644
--- a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
+++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
@@ -11,6 +11,8 @@
     unconditional_panic
 )]
 #![feature(const_mut_refs)]
+#![feature(f128)]
+#![feature(f16)]
 #![warn(clippy::arithmetic_side_effects)]
 
 extern crate proc_macro_derive;
@@ -162,8 +164,10 @@ pub fn association_with_structures_should_not_trigger_the_lint() {
 }
 
 pub fn hard_coded_allowed() {
+    let _ = 1f16 + 1f16;
     let _ = 1f32 + 1f32;
     let _ = 1f64 + 1f64;
+    let _ = 1f128 + 1f128;
 
     let _ = Saturating(0u32) + Saturating(0u32);
     let _ = String::new() + "";
diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr
index 8039c0bfa24..78914667bf3 100644
--- a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr
+++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr
@@ -1,731 +1,743 @@
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:304:5
+  --> tests/ui/arithmetic_side_effects.rs:167:13
    |
-LL |     _n += 1;
-   |     ^^^^^^^
+LL |     let _ = 1f16 + 1f16;
+   |             ^^^^^^^^^^^
    |
    = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::arithmetic_side_effects)]`
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:305:5
+  --> tests/ui/arithmetic_side_effects.rs:170:13
+   |
+LL |     let _ = 1f128 + 1f128;
+   |             ^^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> tests/ui/arithmetic_side_effects.rs:308:5
+   |
+LL |     _n += 1;
+   |     ^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> tests/ui/arithmetic_side_effects.rs:309:5
    |
 LL |     _n += &1;
    |     ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:306:5
+  --> tests/ui/arithmetic_side_effects.rs:310:5
    |
 LL |     _n -= 1;
    |     ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:307:5
+  --> tests/ui/arithmetic_side_effects.rs:311:5
    |
 LL |     _n -= &1;
    |     ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:308:5
+  --> tests/ui/arithmetic_side_effects.rs:312:5
    |
 LL |     _n /= 0;
    |     ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:309:5
+  --> tests/ui/arithmetic_side_effects.rs:313:5
    |
 LL |     _n /= &0;
    |     ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:310:5
+  --> tests/ui/arithmetic_side_effects.rs:314:5
    |
 LL |     _n %= 0;
    |     ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:311:5
+  --> tests/ui/arithmetic_side_effects.rs:315:5
    |
 LL |     _n %= &0;
    |     ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:312:5
+  --> tests/ui/arithmetic_side_effects.rs:316:5
    |
 LL |     _n *= 2;
    |     ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:313:5
+  --> tests/ui/arithmetic_side_effects.rs:317:5
    |
 LL |     _n *= &2;
    |     ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:314:5
+  --> tests/ui/arithmetic_side_effects.rs:318:5
    |
 LL |     _n += -1;
    |     ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:315:5
+  --> tests/ui/arithmetic_side_effects.rs:319:5
    |
 LL |     _n += &-1;
    |     ^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:316:5
+  --> tests/ui/arithmetic_side_effects.rs:320:5
    |
 LL |     _n -= -1;
    |     ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:317:5
+  --> tests/ui/arithmetic_side_effects.rs:321:5
    |
 LL |     _n -= &-1;
    |     ^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:318:5
+  --> tests/ui/arithmetic_side_effects.rs:322:5
    |
 LL |     _n /= -0;
    |     ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:319:5
+  --> tests/ui/arithmetic_side_effects.rs:323:5
    |
 LL |     _n /= &-0;
    |     ^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:320:5
+  --> tests/ui/arithmetic_side_effects.rs:324:5
    |
 LL |     _n %= -0;
    |     ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:321:5
+  --> tests/ui/arithmetic_side_effects.rs:325:5
    |
 LL |     _n %= &-0;
    |     ^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:322:5
+  --> tests/ui/arithmetic_side_effects.rs:326:5
    |
 LL |     _n *= -2;
    |     ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:323:5
+  --> tests/ui/arithmetic_side_effects.rs:327:5
    |
 LL |     _n *= &-2;
    |     ^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:324:5
+  --> tests/ui/arithmetic_side_effects.rs:328:5
    |
 LL |     _custom += Custom;
    |     ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:325:5
+  --> tests/ui/arithmetic_side_effects.rs:329:5
    |
 LL |     _custom += &Custom;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:326:5
+  --> tests/ui/arithmetic_side_effects.rs:330:5
    |
 LL |     _custom -= Custom;
    |     ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:327:5
+  --> tests/ui/arithmetic_side_effects.rs:331:5
    |
 LL |     _custom -= &Custom;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:328:5
+  --> tests/ui/arithmetic_side_effects.rs:332:5
    |
 LL |     _custom /= Custom;
    |     ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:329:5
+  --> tests/ui/arithmetic_side_effects.rs:333:5
    |
 LL |     _custom /= &Custom;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:330:5
+  --> tests/ui/arithmetic_side_effects.rs:334:5
    |
 LL |     _custom %= Custom;
    |     ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:331:5
+  --> tests/ui/arithmetic_side_effects.rs:335:5
    |
 LL |     _custom %= &Custom;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:332:5
+  --> tests/ui/arithmetic_side_effects.rs:336:5
    |
 LL |     _custom *= Custom;
    |     ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:333:5
+  --> tests/ui/arithmetic_side_effects.rs:337:5
    |
 LL |     _custom *= &Custom;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:334:5
+  --> tests/ui/arithmetic_side_effects.rs:338:5
    |
 LL |     _custom >>= Custom;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:335:5
+  --> tests/ui/arithmetic_side_effects.rs:339:5
    |
 LL |     _custom >>= &Custom;
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:336:5
+  --> tests/ui/arithmetic_side_effects.rs:340:5
    |
 LL |     _custom <<= Custom;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:337:5
+  --> tests/ui/arithmetic_side_effects.rs:341:5
    |
 LL |     _custom <<= &Custom;
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:338:5
+  --> tests/ui/arithmetic_side_effects.rs:342:5
    |
 LL |     _custom += -Custom;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:339:5
+  --> tests/ui/arithmetic_side_effects.rs:343:5
    |
 LL |     _custom += &-Custom;
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:340:5
+  --> tests/ui/arithmetic_side_effects.rs:344:5
    |
 LL |     _custom -= -Custom;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:341:5
+  --> tests/ui/arithmetic_side_effects.rs:345:5
    |
 LL |     _custom -= &-Custom;
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:342:5
+  --> tests/ui/arithmetic_side_effects.rs:346:5
    |
 LL |     _custom /= -Custom;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:343:5
+  --> tests/ui/arithmetic_side_effects.rs:347:5
    |
 LL |     _custom /= &-Custom;
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:344:5
+  --> tests/ui/arithmetic_side_effects.rs:348:5
    |
 LL |     _custom %= -Custom;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:345:5
+  --> tests/ui/arithmetic_side_effects.rs:349:5
    |
 LL |     _custom %= &-Custom;
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:346:5
+  --> tests/ui/arithmetic_side_effects.rs:350:5
    |
 LL |     _custom *= -Custom;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:347:5
+  --> tests/ui/arithmetic_side_effects.rs:351:5
    |
 LL |     _custom *= &-Custom;
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:348:5
+  --> tests/ui/arithmetic_side_effects.rs:352:5
    |
 LL |     _custom >>= -Custom;
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:349:5
+  --> tests/ui/arithmetic_side_effects.rs:353:5
    |
 LL |     _custom >>= &-Custom;
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:350:5
+  --> tests/ui/arithmetic_side_effects.rs:354:5
    |
 LL |     _custom <<= -Custom;
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:351:5
+  --> tests/ui/arithmetic_side_effects.rs:355:5
    |
 LL |     _custom <<= &-Custom;
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:354:10
+  --> tests/ui/arithmetic_side_effects.rs:358:10
    |
 LL |     _n = _n + 1;
    |          ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:355:10
+  --> tests/ui/arithmetic_side_effects.rs:359:10
    |
 LL |     _n = _n + &1;
    |          ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:356:10
+  --> tests/ui/arithmetic_side_effects.rs:360:10
    |
 LL |     _n = 1 + _n;
    |          ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:357:10
+  --> tests/ui/arithmetic_side_effects.rs:361:10
    |
 LL |     _n = &1 + _n;
    |          ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:358:10
+  --> tests/ui/arithmetic_side_effects.rs:362:10
    |
 LL |     _n = _n - 1;
    |          ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:359:10
+  --> tests/ui/arithmetic_side_effects.rs:363:10
    |
 LL |     _n = _n - &1;
    |          ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:360:10
+  --> tests/ui/arithmetic_side_effects.rs:364:10
    |
 LL |     _n = 1 - _n;
    |          ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:361:10
+  --> tests/ui/arithmetic_side_effects.rs:365:10
    |
 LL |     _n = &1 - _n;
    |          ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:362:10
+  --> tests/ui/arithmetic_side_effects.rs:366:10
    |
 LL |     _n = _n / 0;
    |          ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:363:10
+  --> tests/ui/arithmetic_side_effects.rs:367:10
    |
 LL |     _n = _n / &0;
    |          ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:364:10
+  --> tests/ui/arithmetic_side_effects.rs:368:10
    |
 LL |     _n = _n % 0;
    |          ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:365:10
+  --> tests/ui/arithmetic_side_effects.rs:369:10
    |
 LL |     _n = _n % &0;
    |          ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:366:10
+  --> tests/ui/arithmetic_side_effects.rs:370:10
    |
 LL |     _n = _n * 2;
    |          ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:367:10
+  --> tests/ui/arithmetic_side_effects.rs:371:10
    |
 LL |     _n = _n * &2;
    |          ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:368:10
+  --> tests/ui/arithmetic_side_effects.rs:372:10
    |
 LL |     _n = 2 * _n;
    |          ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:369:10
+  --> tests/ui/arithmetic_side_effects.rs:373:10
    |
 LL |     _n = &2 * _n;
    |          ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:370:10
+  --> tests/ui/arithmetic_side_effects.rs:374:10
    |
 LL |     _n = 23 + &85;
    |          ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:371:10
+  --> tests/ui/arithmetic_side_effects.rs:375:10
    |
 LL |     _n = &23 + 85;
    |          ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:372:10
+  --> tests/ui/arithmetic_side_effects.rs:376:10
    |
 LL |     _n = &23 + &85;
    |          ^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:373:15
+  --> tests/ui/arithmetic_side_effects.rs:377:15
    |
 LL |     _custom = _custom + _custom;
    |               ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:374:15
+  --> tests/ui/arithmetic_side_effects.rs:378:15
    |
 LL |     _custom = _custom + &_custom;
    |               ^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:375:15
+  --> tests/ui/arithmetic_side_effects.rs:379:15
    |
 LL |     _custom = Custom + _custom;
    |               ^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:376:15
+  --> tests/ui/arithmetic_side_effects.rs:380:15
    |
 LL |     _custom = &Custom + _custom;
    |               ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:377:15
+  --> tests/ui/arithmetic_side_effects.rs:381:15
    |
 LL |     _custom = _custom - Custom;
    |               ^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:378:15
+  --> tests/ui/arithmetic_side_effects.rs:382:15
    |
 LL |     _custom = _custom - &Custom;
    |               ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:379:15
+  --> tests/ui/arithmetic_side_effects.rs:383:15
    |
 LL |     _custom = Custom - _custom;
    |               ^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:380:15
+  --> tests/ui/arithmetic_side_effects.rs:384:15
    |
 LL |     _custom = &Custom - _custom;
    |               ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:381:15
+  --> tests/ui/arithmetic_side_effects.rs:385:15
    |
 LL |     _custom = _custom / Custom;
    |               ^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:382:15
+  --> tests/ui/arithmetic_side_effects.rs:386:15
    |
 LL |     _custom = _custom / &Custom;
    |               ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:383:15
+  --> tests/ui/arithmetic_side_effects.rs:387:15
    |
 LL |     _custom = _custom % Custom;
    |               ^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:384:15
+  --> tests/ui/arithmetic_side_effects.rs:388:15
    |
 LL |     _custom = _custom % &Custom;
    |               ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:385:15
+  --> tests/ui/arithmetic_side_effects.rs:389:15
    |
 LL |     _custom = _custom * Custom;
    |               ^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:386:15
+  --> tests/ui/arithmetic_side_effects.rs:390:15
    |
 LL |     _custom = _custom * &Custom;
    |               ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:387:15
+  --> tests/ui/arithmetic_side_effects.rs:391:15
    |
 LL |     _custom = Custom * _custom;
    |               ^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:388:15
+  --> tests/ui/arithmetic_side_effects.rs:392:15
    |
 LL |     _custom = &Custom * _custom;
    |               ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:389:15
+  --> tests/ui/arithmetic_side_effects.rs:393:15
    |
 LL |     _custom = Custom + &Custom;
    |               ^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:390:15
+  --> tests/ui/arithmetic_side_effects.rs:394:15
    |
 LL |     _custom = &Custom + Custom;
    |               ^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:391:15
+  --> tests/ui/arithmetic_side_effects.rs:395:15
    |
 LL |     _custom = &Custom + &Custom;
    |               ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:392:15
+  --> tests/ui/arithmetic_side_effects.rs:396:15
    |
 LL |     _custom = _custom >> _custom;
    |               ^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:393:15
+  --> tests/ui/arithmetic_side_effects.rs:397:15
    |
 LL |     _custom = _custom >> &_custom;
    |               ^^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:394:15
+  --> tests/ui/arithmetic_side_effects.rs:398:15
    |
 LL |     _custom = Custom << _custom;
    |               ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:395:15
+  --> tests/ui/arithmetic_side_effects.rs:399:15
    |
 LL |     _custom = &Custom << _custom;
    |               ^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:398:23
+  --> tests/ui/arithmetic_side_effects.rs:402:23
    |
 LL |     _n.saturating_div(0);
    |                       ^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:399:21
+  --> tests/ui/arithmetic_side_effects.rs:403:21
    |
 LL |     _n.wrapping_div(0);
    |                     ^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:400:21
+  --> tests/ui/arithmetic_side_effects.rs:404:21
    |
 LL |     _n.wrapping_rem(0);
    |                     ^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:401:28
+  --> tests/ui/arithmetic_side_effects.rs:405:28
    |
 LL |     _n.wrapping_rem_euclid(0);
    |                            ^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:403:23
+  --> tests/ui/arithmetic_side_effects.rs:407:23
    |
 LL |     _n.saturating_div(_n);
    |                       ^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:404:21
+  --> tests/ui/arithmetic_side_effects.rs:408:21
    |
 LL |     _n.wrapping_div(_n);
    |                     ^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:405:21
+  --> tests/ui/arithmetic_side_effects.rs:409:21
    |
 LL |     _n.wrapping_rem(_n);
    |                     ^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:406:28
+  --> tests/ui/arithmetic_side_effects.rs:410:28
    |
 LL |     _n.wrapping_rem_euclid(_n);
    |                            ^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:409:10
+  --> tests/ui/arithmetic_side_effects.rs:413:10
    |
 LL |     _n = -_n;
    |          ^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:410:10
+  --> tests/ui/arithmetic_side_effects.rs:414:10
    |
 LL |     _n = -&_n;
    |          ^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:411:15
+  --> tests/ui/arithmetic_side_effects.rs:415:15
    |
 LL |     _custom = -_custom;
    |               ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:412:15
+  --> tests/ui/arithmetic_side_effects.rs:416:15
    |
 LL |     _custom = -&_custom;
    |               ^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:421:5
+  --> tests/ui/arithmetic_side_effects.rs:425:5
    |
 LL |     1 + i;
    |     ^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:422:5
+  --> tests/ui/arithmetic_side_effects.rs:426:5
    |
 LL |     i * 2;
    |     ^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:423:5
+  --> tests/ui/arithmetic_side_effects.rs:427:5
    |
 LL |     1 % i / 2;
    |     ^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:424:5
+  --> tests/ui/arithmetic_side_effects.rs:428:5
    |
 LL |     i - 2 + 2 - i;
    |     ^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:425:5
+  --> tests/ui/arithmetic_side_effects.rs:429:5
    |
 LL |     -i;
    |     ^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:436:5
+  --> tests/ui/arithmetic_side_effects.rs:440:5
    |
 LL |     i += 1;
    |     ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:437:5
+  --> tests/ui/arithmetic_side_effects.rs:441:5
    |
 LL |     i -= 1;
    |     ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:438:5
+  --> tests/ui/arithmetic_side_effects.rs:442:5
    |
 LL |     i *= 2;
    |     ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:440:5
+  --> tests/ui/arithmetic_side_effects.rs:444:5
    |
 LL |     i /= 0;
    |     ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:442:5
+  --> tests/ui/arithmetic_side_effects.rs:446:5
    |
 LL |     i /= var1;
    |     ^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:443:5
+  --> tests/ui/arithmetic_side_effects.rs:447:5
    |
 LL |     i /= var2;
    |     ^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:445:5
+  --> tests/ui/arithmetic_side_effects.rs:449:5
    |
 LL |     i %= 0;
    |     ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:447:5
+  --> tests/ui/arithmetic_side_effects.rs:451:5
    |
 LL |     i %= var1;
    |     ^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:448:5
+  --> tests/ui/arithmetic_side_effects.rs:452:5
    |
 LL |     i %= var2;
    |     ^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:458:5
+  --> tests/ui/arithmetic_side_effects.rs:462:5
    |
 LL |     10 / a
    |     ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:512:9
+  --> tests/ui/arithmetic_side_effects.rs:516:9
    |
 LL |         x / maybe_zero
    |         ^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:516:9
+  --> tests/ui/arithmetic_side_effects.rs:520:9
    |
 LL |         x % maybe_zero
    |         ^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:527:5
+  --> tests/ui/arithmetic_side_effects.rs:531:5
    |
 LL |     one.add_assign(1);
    |     ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> tests/ui/arithmetic_side_effects.rs:531:5
+  --> tests/ui/arithmetic_side_effects.rs:535:5
    |
 LL |     one.sub_assign(1);
    |     ^^^^^^^^^^^^^^^^^
 
-error: aborting due to 121 previous errors
+error: aborting due to 123 previous errors
 
diff --git a/src/tools/clippy/tests/ui/assigning_clones.fixed b/src/tools/clippy/tests/ui/assigning_clones.fixed
index 70ab43b49b3..60f6a385fc5 100644
--- a/src/tools/clippy/tests/ui/assigning_clones.fixed
+++ b/src/tools/clippy/tests/ui/assigning_clones.fixed
@@ -272,3 +272,59 @@ impl<'a> Add for &'a mut HasCloneFrom {
         self
     }
 }
+
+mod borrowck_conflicts {
+    //! Cases where clone_into and friends cannot be used because the src/dest have conflicting
+    //! borrows.
+    use std::path::PathBuf;
+
+    fn issue12444(mut name: String) {
+        let parts = name.split(", ").collect::<Vec<_>>();
+        let first = *parts.first().unwrap();
+        name = first.to_owned();
+    }
+
+    fn issue12444_simple() {
+        let mut s = String::new();
+        let s2 = &s;
+        s = s2.to_owned();
+    }
+
+    fn issue12444_nodrop_projections() {
+        struct NoDrop;
+
+        impl Clone for NoDrop {
+            fn clone(&self) -> Self {
+                todo!()
+            }
+            fn clone_from(&mut self, other: &Self) {
+                todo!()
+            }
+        }
+
+        let mut s = NoDrop;
+        let s2 = &s;
+        s = s2.clone();
+
+        let mut s = (NoDrop, NoDrop);
+        let s2 = &s.0;
+        s.0 = s2.clone();
+
+        // This *could* emit a warning, but PossibleBorrowerMap only works with locals so it
+        // considers `s` fully borrowed
+        let mut s = (NoDrop, NoDrop);
+        let s2 = &s.1;
+        s.0 = s2.clone();
+    }
+
+    fn issue12460(mut name: String) {
+        if let Some(stripped_name) = name.strip_prefix("baz-") {
+            name = stripped_name.to_owned();
+        }
+    }
+
+    fn issue12749() {
+        let mut path = PathBuf::from("/a/b/c");
+        path = path.components().as_path().to_owned();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/assigning_clones.rs b/src/tools/clippy/tests/ui/assigning_clones.rs
index 9699fed100c..6eb85be511a 100644
--- a/src/tools/clippy/tests/ui/assigning_clones.rs
+++ b/src/tools/clippy/tests/ui/assigning_clones.rs
@@ -272,3 +272,59 @@ impl<'a> Add for &'a mut HasCloneFrom {
         self
     }
 }
+
+mod borrowck_conflicts {
+    //! Cases where clone_into and friends cannot be used because the src/dest have conflicting
+    //! borrows.
+    use std::path::PathBuf;
+
+    fn issue12444(mut name: String) {
+        let parts = name.split(", ").collect::<Vec<_>>();
+        let first = *parts.first().unwrap();
+        name = first.to_owned();
+    }
+
+    fn issue12444_simple() {
+        let mut s = String::new();
+        let s2 = &s;
+        s = s2.to_owned();
+    }
+
+    fn issue12444_nodrop_projections() {
+        struct NoDrop;
+
+        impl Clone for NoDrop {
+            fn clone(&self) -> Self {
+                todo!()
+            }
+            fn clone_from(&mut self, other: &Self) {
+                todo!()
+            }
+        }
+
+        let mut s = NoDrop;
+        let s2 = &s;
+        s = s2.clone();
+
+        let mut s = (NoDrop, NoDrop);
+        let s2 = &s.0;
+        s.0 = s2.clone();
+
+        // This *could* emit a warning, but PossibleBorrowerMap only works with locals so it
+        // considers `s` fully borrowed
+        let mut s = (NoDrop, NoDrop);
+        let s2 = &s.1;
+        s.0 = s2.clone();
+    }
+
+    fn issue12460(mut name: String) {
+        if let Some(stripped_name) = name.strip_prefix("baz-") {
+            name = stripped_name.to_owned();
+        }
+    }
+
+    fn issue12749() {
+        let mut path = PathBuf::from("/a/b/c");
+        path = path.components().as_path().to_owned();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/async_yields_async.fixed b/src/tools/clippy/tests/ui/async_yields_async.fixed
index cfad7813805..208651bab1f 100644
--- a/src/tools/clippy/tests/ui/async_yields_async.fixed
+++ b/src/tools/clippy/tests/ui/async_yields_async.fixed
@@ -1,4 +1,3 @@
-#![feature(lint_reasons)]
 #![feature(async_closure)]
 #![warn(clippy::async_yields_async)]
 #![allow(clippy::redundant_async_block)]
diff --git a/src/tools/clippy/tests/ui/async_yields_async.rs b/src/tools/clippy/tests/ui/async_yields_async.rs
index 7bc26647943..b124c994442 100644
--- a/src/tools/clippy/tests/ui/async_yields_async.rs
+++ b/src/tools/clippy/tests/ui/async_yields_async.rs
@@ -1,4 +1,3 @@
-#![feature(lint_reasons)]
 #![feature(async_closure)]
 #![warn(clippy::async_yields_async)]
 #![allow(clippy::redundant_async_block)]
diff --git a/src/tools/clippy/tests/ui/async_yields_async.stderr b/src/tools/clippy/tests/ui/async_yields_async.stderr
index 991ad7ae0ae..861c3f2ce4a 100644
--- a/src/tools/clippy/tests/ui/async_yields_async.stderr
+++ b/src/tools/clippy/tests/ui/async_yields_async.stderr
@@ -1,5 +1,5 @@
 error: an async construct yields a type which is itself awaitable
-  --> tests/ui/async_yields_async.rs:39:9
+  --> tests/ui/async_yields_async.rs:38:9
    |
 LL |        let _h = async {
    |  _____________________-
@@ -20,7 +20,7 @@ LL +         }.await
    |
 
 error: an async construct yields a type which is itself awaitable
-  --> tests/ui/async_yields_async.rs:44:9
+  --> tests/ui/async_yields_async.rs:43:9
    |
 LL |       let _i = async {
    |  ____________________-
@@ -33,7 +33,7 @@ LL | |     };
    | |_____- outer async construct
 
 error: an async construct yields a type which is itself awaitable
-  --> tests/ui/async_yields_async.rs:50:9
+  --> tests/ui/async_yields_async.rs:49:9
    |
 LL |        let _j = async || {
    |  ________________________-
@@ -52,7 +52,7 @@ LL +         }.await
    |
 
 error: an async construct yields a type which is itself awaitable
-  --> tests/ui/async_yields_async.rs:55:9
+  --> tests/ui/async_yields_async.rs:54:9
    |
 LL |       let _k = async || {
    |  _______________________-
@@ -65,7 +65,7 @@ LL | |     };
    | |_____- outer async construct
 
 error: an async construct yields a type which is itself awaitable
-  --> tests/ui/async_yields_async.rs:57:23
+  --> tests/ui/async_yields_async.rs:56:23
    |
 LL |     let _l = async || CustomFutureType;
    |                       ^^^^^^^^^^^^^^^^
@@ -75,7 +75,7 @@ LL |     let _l = async || CustomFutureType;
    |                       help: consider awaiting this value: `CustomFutureType.await`
 
 error: an async construct yields a type which is itself awaitable
-  --> tests/ui/async_yields_async.rs:63:9
+  --> tests/ui/async_yields_async.rs:62:9
    |
 LL |       let _m = async || {
    |  _______________________-
diff --git a/src/tools/clippy/tests/ui/auxiliary/external_consts.rs b/src/tools/clippy/tests/ui/auxiliary/external_consts.rs
new file mode 100644
index 00000000000..1885ba341f5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/auxiliary/external_consts.rs
@@ -0,0 +1 @@
+pub const MAGIC_NUMBER: i32 = 1;
diff --git a/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr b/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr
index 73255651abe..b15857c325a 100644
--- a/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr
+++ b/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr
@@ -62,7 +62,7 @@ LL |         }
 LL |         match s.len() {
 LL ~             10 => 2,
 LL |             20 => {
- ...
+...
 LL |                         if foo() {
 LL ~                             return 20;
 LL |                         }
diff --git a/src/tools/clippy/tests/ui/boxed_local.rs b/src/tools/clippy/tests/ui/boxed_local.rs
index e888154c46d..fbd9e12fc18 100644
--- a/src/tools/clippy/tests/ui/boxed_local.rs
+++ b/src/tools/clippy/tests/ui/boxed_local.rs
@@ -1,4 +1,3 @@
-#![feature(lint_reasons)]
 #![allow(
     clippy::borrowed_box,
     clippy::needless_pass_by_value,
diff --git a/src/tools/clippy/tests/ui/boxed_local.stderr b/src/tools/clippy/tests/ui/boxed_local.stderr
index d3156c820b2..7710233fa4d 100644
--- a/src/tools/clippy/tests/ui/boxed_local.stderr
+++ b/src/tools/clippy/tests/ui/boxed_local.stderr
@@ -1,5 +1,5 @@
 error: local variable doesn't need to be boxed here
-  --> tests/ui/boxed_local.rs:40:13
+  --> tests/ui/boxed_local.rs:39:13
    |
 LL | fn warn_arg(x: Box<A>) {
    |             ^
@@ -8,19 +8,19 @@ LL | fn warn_arg(x: Box<A>) {
    = help: to override `-D warnings` add `#[allow(clippy::boxed_local)]`
 
 error: local variable doesn't need to be boxed here
-  --> tests/ui/boxed_local.rs:123:12
+  --> tests/ui/boxed_local.rs:122:12
    |
 LL | pub fn new(_needs_name: Box<PeekableSeekable<&()>>) -> () {}
    |            ^^^^^^^^^^^
 
 error: local variable doesn't need to be boxed here
-  --> tests/ui/boxed_local.rs:188:44
+  --> tests/ui/boxed_local.rs:187:44
    |
 LL |         fn default_impl_x(self: Box<Self>, x: Box<u32>) -> u32 {
    |                                            ^
 
 error: local variable doesn't need to be boxed here
-  --> tests/ui/boxed_local.rs:196:16
+  --> tests/ui/boxed_local.rs:195:16
    |
 LL |         fn foo(x: Box<u32>) {}
    |                ^
diff --git a/src/tools/clippy/tests/ui/cast.rs b/src/tools/clippy/tests/ui/cast.rs
index 453d62ce607..146b04ab813 100644
--- a/src/tools/clippy/tests/ui/cast.rs
+++ b/src/tools/clippy/tests/ui/cast.rs
@@ -12,11 +12,14 @@
 #![allow(
     clippy::cast_abs_to_unsigned,
     clippy::no_effect,
+    clippy::unnecessary_min_or_max,
     clippy::unnecessary_operation,
     clippy::unnecessary_literal_unwrap,
     clippy::identity_op
 )]
 
+// FIXME(f16_f128): add tests once const casting is available for these types
+
 fn main() {
     // Test clippy::cast_precision_loss
     let x0 = 1i32;
diff --git a/src/tools/clippy/tests/ui/cast.stderr b/src/tools/clippy/tests/ui/cast.stderr
index 43c0d8f4ed7..7824bdfac25 100644
--- a/src/tools/clippy/tests/ui/cast.stderr
+++ b/src/tools/clippy/tests/ui/cast.stderr
@@ -1,5 +1,5 @@
 error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast.rs:23:5
+  --> tests/ui/cast.rs:26:5
    |
 LL |     x0 as f32;
    |     ^^^^^^^^^
@@ -8,37 +8,37 @@ LL |     x0 as f32;
    = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]`
 
 error: casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast.rs:27:5
+  --> tests/ui/cast.rs:30:5
    |
 LL |     x1 as f32;
    |     ^^^^^^^^^
 
 error: casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
-  --> tests/ui/cast.rs:29:5
+  --> tests/ui/cast.rs:32:5
    |
 LL |     x1 as f64;
    |     ^^^^^^^^^
 
 error: casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast.rs:32:5
+  --> tests/ui/cast.rs:35:5
    |
 LL |     x2 as f32;
    |     ^^^^^^^^^
 
 error: casting `u64` to `f32` causes a loss of precision (`u64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast.rs:35:5
+  --> tests/ui/cast.rs:38:5
    |
 LL |     x3 as f32;
    |     ^^^^^^^^^
 
 error: casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
-  --> tests/ui/cast.rs:37:5
+  --> tests/ui/cast.rs:40:5
    |
 LL |     x3 as f64;
    |     ^^^^^^^^^
 
 error: casting `f32` to `i32` may truncate the value
-  --> tests/ui/cast.rs:40:5
+  --> tests/ui/cast.rs:43:5
    |
 LL |     1f32 as i32;
    |     ^^^^^^^^^^^
@@ -48,7 +48,7 @@ LL |     1f32 as i32;
    = help: to override `-D warnings` add `#[allow(clippy::cast_possible_truncation)]`
 
 error: casting `f32` to `u32` may truncate the value
-  --> tests/ui/cast.rs:42:5
+  --> tests/ui/cast.rs:45:5
    |
 LL |     1f32 as u32;
    |     ^^^^^^^^^^^
@@ -56,7 +56,7 @@ LL |     1f32 as u32;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:42:5
+  --> tests/ui/cast.rs:45:5
    |
 LL |     1f32 as u32;
    |     ^^^^^^^^^^^
@@ -65,7 +65,7 @@ LL |     1f32 as u32;
    = help: to override `-D warnings` add `#[allow(clippy::cast_sign_loss)]`
 
 error: casting `f64` to `f32` may truncate the value
-  --> tests/ui/cast.rs:46:5
+  --> tests/ui/cast.rs:49:5
    |
 LL |     1f64 as f32;
    |     ^^^^^^^^^^^
@@ -73,7 +73,7 @@ LL |     1f64 as f32;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `i32` to `i8` may truncate the value
-  --> tests/ui/cast.rs:48:5
+  --> tests/ui/cast.rs:51:5
    |
 LL |     1i32 as i8;
    |     ^^^^^^^^^^
@@ -85,7 +85,7 @@ LL |     i8::try_from(1i32);
    |     ~~~~~~~~~~~~~~~~~~
 
 error: casting `i32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:50:5
+  --> tests/ui/cast.rs:53:5
    |
 LL |     1i32 as u8;
    |     ^^^^^^^^^^
@@ -97,7 +97,7 @@ LL |     u8::try_from(1i32);
    |     ~~~~~~~~~~~~~~~~~~
 
 error: casting `f64` to `isize` may truncate the value
-  --> tests/ui/cast.rs:52:5
+  --> tests/ui/cast.rs:55:5
    |
 LL |     1f64 as isize;
    |     ^^^^^^^^^^^^^
@@ -105,7 +105,7 @@ LL |     1f64 as isize;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f64` to `usize` may truncate the value
-  --> tests/ui/cast.rs:54:5
+  --> tests/ui/cast.rs:57:5
    |
 LL |     1f64 as usize;
    |     ^^^^^^^^^^^^^
@@ -113,13 +113,13 @@ LL |     1f64 as usize;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f64` to `usize` may lose the sign of the value
-  --> tests/ui/cast.rs:54:5
+  --> tests/ui/cast.rs:57:5
    |
 LL |     1f64 as usize;
    |     ^^^^^^^^^^^^^
 
 error: casting `u32` to `u16` may truncate the value
-  --> tests/ui/cast.rs:57:5
+  --> tests/ui/cast.rs:60:5
    |
 LL |     1f32 as u32 as u16;
    |     ^^^^^^^^^^^^^^^^^^
@@ -131,7 +131,7 @@ LL |     u16::try_from(1f32 as u32);
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `f32` to `u32` may truncate the value
-  --> tests/ui/cast.rs:57:5
+  --> tests/ui/cast.rs:60:5
    |
 LL |     1f32 as u32 as u16;
    |     ^^^^^^^^^^^
@@ -139,13 +139,13 @@ LL |     1f32 as u32 as u16;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:57:5
+  --> tests/ui/cast.rs:60:5
    |
 LL |     1f32 as u32 as u16;
    |     ^^^^^^^^^^^
 
 error: casting `i32` to `i8` may truncate the value
-  --> tests/ui/cast.rs:62:22
+  --> tests/ui/cast.rs:65:22
    |
 LL |         let _x: i8 = 1i32 as _;
    |                      ^^^^^^^^^
@@ -157,7 +157,7 @@ LL |         let _x: i8 = 1i32.try_into();
    |                      ~~~~~~~~~~~~~~~
 
 error: casting `f32` to `i32` may truncate the value
-  --> tests/ui/cast.rs:64:9
+  --> tests/ui/cast.rs:67:9
    |
 LL |         1f32 as i32;
    |         ^^^^^^^^^^^
@@ -165,7 +165,7 @@ LL |         1f32 as i32;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f64` to `i32` may truncate the value
-  --> tests/ui/cast.rs:66:9
+  --> tests/ui/cast.rs:69:9
    |
 LL |         1f64 as i32;
    |         ^^^^^^^^^^^
@@ -173,7 +173,7 @@ LL |         1f64 as i32;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:68:9
+  --> tests/ui/cast.rs:71:9
    |
 LL |         1f32 as u8;
    |         ^^^^^^^^^^
@@ -181,13 +181,13 @@ LL |         1f32 as u8;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f32` to `u8` may lose the sign of the value
-  --> tests/ui/cast.rs:68:9
+  --> tests/ui/cast.rs:71:9
    |
 LL |         1f32 as u8;
    |         ^^^^^^^^^^
 
 error: casting `u8` to `i8` may wrap around the value
-  --> tests/ui/cast.rs:73:5
+  --> tests/ui/cast.rs:76:5
    |
 LL |     1u8 as i8;
    |     ^^^^^^^^^
@@ -196,31 +196,31 @@ LL |     1u8 as i8;
    = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]`
 
 error: casting `u16` to `i16` may wrap around the value
-  --> tests/ui/cast.rs:76:5
+  --> tests/ui/cast.rs:79:5
    |
 LL |     1u16 as i16;
    |     ^^^^^^^^^^^
 
 error: casting `u32` to `i32` may wrap around the value
-  --> tests/ui/cast.rs:78:5
+  --> tests/ui/cast.rs:81:5
    |
 LL |     1u32 as i32;
    |     ^^^^^^^^^^^
 
 error: casting `u64` to `i64` may wrap around the value
-  --> tests/ui/cast.rs:80:5
+  --> tests/ui/cast.rs:83:5
    |
 LL |     1u64 as i64;
    |     ^^^^^^^^^^^
 
 error: casting `usize` to `isize` may wrap around the value
-  --> tests/ui/cast.rs:82:5
+  --> tests/ui/cast.rs:85:5
    |
 LL |     1usize as isize;
    |     ^^^^^^^^^^^^^^^
 
 error: casting `usize` to `i8` may truncate the value
-  --> tests/ui/cast.rs:85:5
+  --> tests/ui/cast.rs:88:5
    |
 LL |     1usize as i8;
    |     ^^^^^^^^^^^^
@@ -232,7 +232,7 @@ LL |     i8::try_from(1usize);
    |     ~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `i16` may truncate the value
-  --> tests/ui/cast.rs:88:5
+  --> tests/ui/cast.rs:91:5
    |
 LL |     1usize as i16;
    |     ^^^^^^^^^^^^^
@@ -244,7 +244,7 @@ LL |     i16::try_from(1usize);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `i16` may wrap around the value on targets with 16-bit wide pointers
-  --> tests/ui/cast.rs:88:5
+  --> tests/ui/cast.rs:91:5
    |
 LL |     1usize as i16;
    |     ^^^^^^^^^^^^^
@@ -253,7 +253,7 @@ LL |     1usize as i16;
    = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types
 
 error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers
-  --> tests/ui/cast.rs:93:5
+  --> tests/ui/cast.rs:96:5
    |
 LL |     1usize as i32;
    |     ^^^^^^^^^^^^^
@@ -265,19 +265,19 @@ LL |     i32::try_from(1usize);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:93:5
+  --> tests/ui/cast.rs:96:5
    |
 LL |     1usize as i32;
    |     ^^^^^^^^^^^^^
 
 error: casting `usize` to `i64` may wrap around the value on targets with 64-bit wide pointers
-  --> tests/ui/cast.rs:97:5
+  --> tests/ui/cast.rs:100:5
    |
 LL |     1usize as i64;
    |     ^^^^^^^^^^^^^
 
 error: casting `u16` to `isize` may wrap around the value on targets with 16-bit wide pointers
-  --> tests/ui/cast.rs:102:5
+  --> tests/ui/cast.rs:105:5
    |
 LL |     1u16 as isize;
    |     ^^^^^^^^^^^^^
@@ -286,13 +286,13 @@ LL |     1u16 as isize;
    = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types
 
 error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:106:5
+  --> tests/ui/cast.rs:109:5
    |
 LL |     1u32 as isize;
    |     ^^^^^^^^^^^^^
 
 error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:109:5
+  --> tests/ui/cast.rs:112:5
    |
 LL |     1u64 as isize;
    |     ^^^^^^^^^^^^^
@@ -304,55 +304,55 @@ LL |     isize::try_from(1u64);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers
-  --> tests/ui/cast.rs:109:5
+  --> tests/ui/cast.rs:112:5
    |
 LL |     1u64 as isize;
    |     ^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:114:5
+  --> tests/ui/cast.rs:117:5
    |
 LL |     -1i32 as u32;
    |     ^^^^^^^^^^^^
 
 error: casting `isize` to `usize` may lose the sign of the value
-  --> tests/ui/cast.rs:117:5
+  --> tests/ui/cast.rs:120:5
    |
 LL |     -1isize as usize;
    |     ^^^^^^^^^^^^^^^^
 
 error: casting `i8` to `u8` may lose the sign of the value
-  --> tests/ui/cast.rs:128:5
+  --> tests/ui/cast.rs:131:5
    |
 LL |     (i8::MIN).abs() as u8;
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i64` to `u64` may lose the sign of the value
-  --> tests/ui/cast.rs:132:5
+  --> tests/ui/cast.rs:135:5
    |
 LL |     (-1i64).abs() as u64;
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: casting `isize` to `usize` may lose the sign of the value
-  --> tests/ui/cast.rs:133:5
+  --> tests/ui/cast.rs:136:5
    |
 LL |     (-1isize).abs() as usize;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i64` to `u64` may lose the sign of the value
-  --> tests/ui/cast.rs:140:5
+  --> tests/ui/cast.rs:143:5
    |
 LL |     (unsafe { (-1i64).checked_abs().unwrap_unchecked() }) as u64;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i64` to `u64` may lose the sign of the value
-  --> tests/ui/cast.rs:155:5
+  --> tests/ui/cast.rs:158:5
    |
 LL |     (unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }) as u64;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i64` to `i8` may truncate the value
-  --> tests/ui/cast.rs:206:5
+  --> tests/ui/cast.rs:209:5
    |
 LL |     (-99999999999i64).min(1) as i8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -364,7 +364,7 @@ LL |     i8::try_from((-99999999999i64).min(1));
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u64` to `u8` may truncate the value
-  --> tests/ui/cast.rs:220:5
+  --> tests/ui/cast.rs:223:5
    |
 LL |     999999u64.clamp(0, 256) as u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -376,7 +376,7 @@ LL |     u8::try_from(999999u64.clamp(0, 256));
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E2` to `u8` may truncate the value
-  --> tests/ui/cast.rs:243:21
+  --> tests/ui/cast.rs:246:21
    |
 LL |             let _ = self as u8;
    |                     ^^^^^^^^^^
@@ -388,7 +388,7 @@ LL |             let _ = u8::try_from(self);
    |                     ~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E2::B` to `u8` will truncate the value
-  --> tests/ui/cast.rs:245:21
+  --> tests/ui/cast.rs:248:21
    |
 LL |             let _ = Self::B as u8;
    |                     ^^^^^^^^^^^^^
@@ -397,7 +397,7 @@ LL |             let _ = Self::B as u8;
    = help: to override `-D warnings` add `#[allow(clippy::cast_enum_truncation)]`
 
 error: casting `main::E5` to `i8` may truncate the value
-  --> tests/ui/cast.rs:287:21
+  --> tests/ui/cast.rs:290:21
    |
 LL |             let _ = self as i8;
    |                     ^^^^^^^^^^
@@ -409,13 +409,13 @@ LL |             let _ = i8::try_from(self);
    |                     ~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E5::A` to `i8` will truncate the value
-  --> tests/ui/cast.rs:289:21
+  --> tests/ui/cast.rs:292:21
    |
 LL |             let _ = Self::A as i8;
    |                     ^^^^^^^^^^^^^
 
 error: casting `main::E6` to `i16` may truncate the value
-  --> tests/ui/cast.rs:306:21
+  --> tests/ui/cast.rs:309:21
    |
 LL |             let _ = self as i16;
    |                     ^^^^^^^^^^^
@@ -427,7 +427,7 @@ LL |             let _ = i16::try_from(self);
    |                     ~~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:325:21
+  --> tests/ui/cast.rs:328:21
    |
 LL |             let _ = self as usize;
    |                     ^^^^^^^^^^^^^
@@ -439,7 +439,7 @@ LL |             let _ = usize::try_from(self);
    |                     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E10` to `u16` may truncate the value
-  --> tests/ui/cast.rs:372:21
+  --> tests/ui/cast.rs:375:21
    |
 LL |             let _ = self as u16;
    |                     ^^^^^^^^^^^
@@ -451,7 +451,7 @@ LL |             let _ = u16::try_from(self);
    |                     ~~~~~~~~~~~~~~~~~~~
 
 error: casting `u32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:383:13
+  --> tests/ui/cast.rs:386:13
    |
 LL |     let c = (q >> 16) as u8;
    |             ^^^^^^^^^^^^^^^
@@ -463,7 +463,7 @@ LL |     let c = u8::try_from(q >> 16);
    |             ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:387:13
+  --> tests/ui/cast.rs:390:13
    |
 LL |     let c = (q / 1000) as u8;
    |             ^^^^^^^^^^^^^^^^
@@ -475,85 +475,85 @@ LL |     let c = u8::try_from(q / 1000);
    |             ~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:399:9
+  --> tests/ui/cast.rs:402:9
    |
 LL |         (x * x) as u32;
    |         ^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:404:32
+  --> tests/ui/cast.rs:407:32
    |
 LL |     let _a = |x: i32| -> u32 { (x * x * x * x) as u32 };
    |                                ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:406:5
+  --> tests/ui/cast.rs:409:5
    |
 LL |     (2_i32).checked_pow(3).unwrap() as u32;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:407:5
+  --> tests/ui/cast.rs:410:5
    |
 LL |     (-2_i32).pow(3) as u32;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:412:5
+  --> tests/ui/cast.rs:415:5
    |
 LL |     (-5_i32 % 2) as u32;
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:414:5
+  --> tests/ui/cast.rs:417:5
    |
 LL |     (-5_i32 % -2) as u32;
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:417:5
+  --> tests/ui/cast.rs:420:5
    |
 LL |     (-2_i32 >> 1) as u32;
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:421:5
+  --> tests/ui/cast.rs:424:5
    |
 LL |     (x * x) as u32;
    |     ^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:422:5
+  --> tests/ui/cast.rs:425:5
    |
 LL |     (x * x * x) as u32;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:426:5
+  --> tests/ui/cast.rs:429:5
    |
 LL |     (y * y * y * y * -2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:428:5
+  --> tests/ui/cast.rs:431:5
    |
 LL |     (y * y * y / y * 2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:429:5
+  --> tests/ui/cast.rs:432:5
    |
 LL |     (y * y / y * 2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:431:5
+  --> tests/ui/cast.rs:434:5
    |
 LL |     (y / y * y * -2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `/`
-  --> tests/ui/cast.rs:431:6
+  --> tests/ui/cast.rs:434:6
    |
 LL |     (y / y * y * -2) as u16;
    |      ^^^^^
@@ -561,97 +561,97 @@ LL |     (y / y * y * -2) as u16;
    = note: `#[deny(clippy::eq_op)]` on by default
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:434:5
+  --> tests/ui/cast.rs:437:5
    |
 LL |     (y + y + y + -2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:436:5
+  --> tests/ui/cast.rs:439:5
    |
 LL |     (y + y + y + 2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:440:5
+  --> tests/ui/cast.rs:443:5
    |
 LL |     (z + -2) as u16;
    |     ^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:442:5
+  --> tests/ui/cast.rs:445:5
    |
 LL |     (z + z + 2) as u16;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:445:9
+  --> tests/ui/cast.rs:448:9
    |
 LL |         (a * a * b * b * c * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:446:9
+  --> tests/ui/cast.rs:449:9
    |
 LL |         (a * b * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:448:9
+  --> tests/ui/cast.rs:451:9
    |
 LL |         (a * -b * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:450:9
+  --> tests/ui/cast.rs:453:9
    |
 LL |         (a * b * c * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:451:9
+  --> tests/ui/cast.rs:454:9
    |
 LL |         (a * -2) as u32;
    |         ^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:453:9
+  --> tests/ui/cast.rs:456:9
    |
 LL |         (a * b * c * -2) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:455:9
+  --> tests/ui/cast.rs:458:9
    |
 LL |         (a / b) as u32;
    |         ^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:456:9
+  --> tests/ui/cast.rs:459:9
    |
 LL |         (a / b * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:458:9
+  --> tests/ui/cast.rs:461:9
    |
 LL |         (a / b + b * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:460:9
+  --> tests/ui/cast.rs:463:9
    |
 LL |         a.saturating_pow(3) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:462:9
+  --> tests/ui/cast.rs:465:9
    |
 LL |         (a.abs() * b.pow(2) / c.abs()) as u32
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:470:21
+  --> tests/ui/cast.rs:473:21
    |
 LL |             let _ = i32::MIN as u32; // cast_sign_loss
    |                     ^^^^^^^^^^^^^^^
@@ -662,7 +662,7 @@ LL |     m!();
    = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: casting `u32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:471:21
+  --> tests/ui/cast.rs:474:21
    |
 LL |             let _ = u32::MAX as u8; // cast_possible_truncation
    |                     ^^^^^^^^^^^^^^
@@ -678,7 +678,7 @@ LL |             let _ = u8::try_from(u32::MAX); // cast_possible_truncation
    |                     ~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `f64` to `f32` may truncate the value
-  --> tests/ui/cast.rs:472:21
+  --> tests/ui/cast.rs:475:21
    |
 LL |             let _ = std::f64::consts::PI as f32; // cast_possible_truncation
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -690,7 +690,7 @@ LL |     m!();
    = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:481:5
+  --> tests/ui/cast.rs:484:5
    |
 LL |     bar.unwrap().unwrap() as usize
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -702,13 +702,13 @@ LL |     usize::try_from(bar.unwrap().unwrap())
    |
 
 error: casting `i64` to `usize` may lose the sign of the value
-  --> tests/ui/cast.rs:481:5
+  --> tests/ui/cast.rs:484:5
    |
 LL |     bar.unwrap().unwrap() as usize
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `u64` to `u8` may truncate the value
-  --> tests/ui/cast.rs:496:5
+  --> tests/ui/cast.rs:499:5
    |
 LL |     (256 & 999999u64) as u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
@@ -720,7 +720,7 @@ LL |     u8::try_from(256 & 999999u64);
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u64` to `u8` may truncate the value
-  --> tests/ui/cast.rs:498:5
+  --> tests/ui/cast.rs:501:5
    |
 LL |     (255 % 999999u64) as u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/cast_lossless_float.fixed b/src/tools/clippy/tests/ui/cast_lossless_float.fixed
index 96a67b1945c..163432631e1 100644
--- a/src/tools/clippy/tests/ui/cast_lossless_float.fixed
+++ b/src/tools/clippy/tests/ui/cast_lossless_float.fixed
@@ -1,6 +1,8 @@
 #![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)]
 #![warn(clippy::cast_lossless)]
 
+// FIXME(f16_f128): add tests for these types once const casting is available
+
 type F32 = f32;
 type F64 = f64;
 
diff --git a/src/tools/clippy/tests/ui/cast_lossless_float.rs b/src/tools/clippy/tests/ui/cast_lossless_float.rs
index d37b2c1d920..afb2a3d890e 100644
--- a/src/tools/clippy/tests/ui/cast_lossless_float.rs
+++ b/src/tools/clippy/tests/ui/cast_lossless_float.rs
@@ -1,6 +1,8 @@
 #![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)]
 #![warn(clippy::cast_lossless)]
 
+// FIXME(f16_f128): add tests for these types once const casting is available
+
 type F32 = f32;
 type F64 = f64;
 
diff --git a/src/tools/clippy/tests/ui/cast_lossless_float.stderr b/src/tools/clippy/tests/ui/cast_lossless_float.stderr
index ad7de760adf..f2ba4e3b990 100644
--- a/src/tools/clippy/tests/ui/cast_lossless_float.stderr
+++ b/src/tools/clippy/tests/ui/cast_lossless_float.stderr
@@ -1,5 +1,5 @@
 error: casting `i8` to `f32` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_float.rs:10:13
+  --> tests/ui/cast_lossless_float.rs:12:13
    |
 LL |     let _ = x0 as f32;
    |             ^^^^^^^^^ help: try: `f32::from(x0)`
@@ -8,73 +8,73 @@ LL |     let _ = x0 as f32;
    = help: to override `-D warnings` add `#[allow(clippy::cast_lossless)]`
 
 error: casting `i8` to `f64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_float.rs:11:13
+  --> tests/ui/cast_lossless_float.rs:13:13
    |
 LL |     let _ = x0 as f64;
    |             ^^^^^^^^^ help: try: `f64::from(x0)`
 
 error: casting `i8` to `F32` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_float.rs:12:13
+  --> tests/ui/cast_lossless_float.rs:14:13
    |
 LL |     let _ = x0 as F32;
    |             ^^^^^^^^^ help: try: `F32::from(x0)`
 
 error: casting `i8` to `F64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_float.rs:13:13
+  --> tests/ui/cast_lossless_float.rs:15:13
    |
 LL |     let _ = x0 as F64;
    |             ^^^^^^^^^ help: try: `F64::from(x0)`
 
 error: casting `u8` to `f32` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_float.rs:15:13
+  --> tests/ui/cast_lossless_float.rs:17:13
    |
 LL |     let _ = x1 as f32;
    |             ^^^^^^^^^ help: try: `f32::from(x1)`
 
 error: casting `u8` to `f64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_float.rs:16:13
+  --> tests/ui/cast_lossless_float.rs:18:13
    |
 LL |     let _ = x1 as f64;
    |             ^^^^^^^^^ help: try: `f64::from(x1)`
 
 error: casting `i16` to `f32` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_float.rs:18:13
+  --> tests/ui/cast_lossless_float.rs:20:13
    |
 LL |     let _ = x2 as f32;
    |             ^^^^^^^^^ help: try: `f32::from(x2)`
 
 error: casting `i16` to `f64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_float.rs:19:13
+  --> tests/ui/cast_lossless_float.rs:21:13
    |
 LL |     let _ = x2 as f64;
    |             ^^^^^^^^^ help: try: `f64::from(x2)`
 
 error: casting `u16` to `f32` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_float.rs:21:13
+  --> tests/ui/cast_lossless_float.rs:23:13
    |
 LL |     let _ = x3 as f32;
    |             ^^^^^^^^^ help: try: `f32::from(x3)`
 
 error: casting `u16` to `f64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_float.rs:22:13
+  --> tests/ui/cast_lossless_float.rs:24:13
    |
 LL |     let _ = x3 as f64;
    |             ^^^^^^^^^ help: try: `f64::from(x3)`
 
 error: casting `i32` to `f64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_float.rs:24:13
+  --> tests/ui/cast_lossless_float.rs:26:13
    |
 LL |     let _ = x4 as f64;
    |             ^^^^^^^^^ help: try: `f64::from(x4)`
 
 error: casting `u32` to `f64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_float.rs:26:13
+  --> tests/ui/cast_lossless_float.rs:28:13
    |
 LL |     let _ = x5 as f64;
    |             ^^^^^^^^^ help: try: `f64::from(x5)`
 
 error: casting `f32` to `f64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_float.rs:29:13
+  --> tests/ui/cast_lossless_float.rs:31:13
    |
 LL |     let _ = 1.0f32 as f64;
    |             ^^^^^^^^^^^^^ help: try: `f64::from(1.0f32)`
diff --git a/src/tools/clippy/tests/ui/cast_nan_to_int.rs b/src/tools/clippy/tests/ui/cast_nan_to_int.rs
index 2d7467ff040..aee38da9a15 100644
--- a/src/tools/clippy/tests/ui/cast_nan_to_int.rs
+++ b/src/tools/clippy/tests/ui/cast_nan_to_int.rs
@@ -1,3 +1,5 @@
+// FIXME(f16_f128): add tests when constants are available
+
 #![warn(clippy::cast_nan_to_int)]
 #![allow(clippy::eq_op)]
 
diff --git a/src/tools/clippy/tests/ui/cast_nan_to_int.stderr b/src/tools/clippy/tests/ui/cast_nan_to_int.stderr
index 3cb46d1e79b..3aeb2d54525 100644
--- a/src/tools/clippy/tests/ui/cast_nan_to_int.stderr
+++ b/src/tools/clippy/tests/ui/cast_nan_to_int.stderr
@@ -1,5 +1,5 @@
 error: casting a known NaN to usize
-  --> tests/ui/cast_nan_to_int.rs:5:13
+  --> tests/ui/cast_nan_to_int.rs:7:13
    |
 LL |     let _ = (0.0_f32 / -0.0) as usize;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -9,7 +9,7 @@ LL |     let _ = (0.0_f32 / -0.0) as usize;
    = help: to override `-D warnings` add `#[allow(clippy::cast_nan_to_int)]`
 
 error: casting a known NaN to usize
-  --> tests/ui/cast_nan_to_int.rs:8:13
+  --> tests/ui/cast_nan_to_int.rs:10:13
    |
 LL |     let _ = (f64::INFINITY * -0.0) as usize;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -17,7 +17,7 @@ LL |     let _ = (f64::INFINITY * -0.0) as usize;
    = note: this always evaluates to 0
 
 error: casting a known NaN to usize
-  --> tests/ui/cast_nan_to_int.rs:11:13
+  --> tests/ui/cast_nan_to_int.rs:13:13
    |
 LL |     let _ = (0.0 * f32::INFINITY) as usize;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -25,7 +25,7 @@ LL |     let _ = (0.0 * f32::INFINITY) as usize;
    = note: this always evaluates to 0
 
 error: casting a known NaN to usize
-  --> tests/ui/cast_nan_to_int.rs:15:13
+  --> tests/ui/cast_nan_to_int.rs:17:13
    |
 LL |     let _ = (f64::INFINITY + f64::NEG_INFINITY) as usize;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -33,7 +33,7 @@ LL |     let _ = (f64::INFINITY + f64::NEG_INFINITY) as usize;
    = note: this always evaluates to 0
 
 error: casting a known NaN to usize
-  --> tests/ui/cast_nan_to_int.rs:18:13
+  --> tests/ui/cast_nan_to_int.rs:20:13
    |
 LL |     let _ = (f32::INFINITY - f32::INFINITY) as usize;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -41,7 +41,7 @@ LL |     let _ = (f32::INFINITY - f32::INFINITY) as usize;
    = note: this always evaluates to 0
 
 error: casting a known NaN to usize
-  --> tests/ui/cast_nan_to_int.rs:21:13
+  --> tests/ui/cast_nan_to_int.rs:23:13
    |
 LL |     let _ = (f32::INFINITY / f32::NEG_INFINITY) as usize;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/cast_size.32bit.stderr b/src/tools/clippy/tests/ui/cast_size.32bit.stderr
index eb6c59deabb..8ff3464676c 100644
--- a/src/tools/clippy/tests/ui/cast_size.32bit.stderr
+++ b/src/tools/clippy/tests/ui/cast_size.32bit.stderr
@@ -12,35 +12,35 @@ help: ... or use `try_from` and handle the error accordingly
 LL |     i8::try_from(1isize);
    |     ~~~~~~~~~~~~~~~~~~~~
 
-error: casting `isize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`isize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
-  --> tests/ui/cast_size.rs:18:5
+error: casting `isize` to `f32` causes a loss of precision (`isize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
+  --> tests/ui/cast_size.rs:21:5
    |
-LL |     x0 as f64;
+LL |     x0 as f32;
    |     ^^^^^^^^^
    |
    = note: `-D clippy::cast-precision-loss` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]`
 
-error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
-  --> tests/ui/cast_size.rs:19:5
+error: casting `usize` to `f32` causes a loss of precision (`usize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
+  --> tests/ui/cast_size.rs:22:5
    |
-LL |     x1 as f64;
+LL |     x1 as f32;
    |     ^^^^^^^^^
 
-error: casting `isize` to `f32` causes a loss of precision (`isize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast_size.rs:20:5
+error: casting `isize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`isize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
+  --> tests/ui/cast_size.rs:23:5
    |
-LL |     x0 as f32;
+LL |     x0 as f64;
    |     ^^^^^^^^^
 
-error: casting `usize` to `f32` causes a loss of precision (`usize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast_size.rs:21:5
+error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
+  --> tests/ui/cast_size.rs:24:5
    |
-LL |     x1 as f32;
+LL |     x1 as f64;
    |     ^^^^^^^^^
 
 error: casting `isize` to `i32` may truncate the value on targets with 64-bit wide pointers
-  --> tests/ui/cast_size.rs:22:5
+  --> tests/ui/cast_size.rs:28:5
    |
 LL |     1isize as i32;
    |     ^^^^^^^^^^^^^
@@ -52,7 +52,7 @@ LL |     i32::try_from(1isize);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `isize` to `u32` may truncate the value on targets with 64-bit wide pointers
-  --> tests/ui/cast_size.rs:23:5
+  --> tests/ui/cast_size.rs:29:5
    |
 LL |     1isize as u32;
    |     ^^^^^^^^^^^^^
@@ -64,7 +64,7 @@ LL |     u32::try_from(1isize);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers
-  --> tests/ui/cast_size.rs:24:5
+  --> tests/ui/cast_size.rs:30:5
    |
 LL |     1usize as u32;
    |     ^^^^^^^^^^^^^
@@ -76,7 +76,7 @@ LL |     u32::try_from(1usize);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers
-  --> tests/ui/cast_size.rs:25:5
+  --> tests/ui/cast_size.rs:31:5
    |
 LL |     1usize as i32;
    |     ^^^^^^^^^^^^^
@@ -88,7 +88,7 @@ LL |     i32::try_from(1usize);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers
-  --> tests/ui/cast_size.rs:25:5
+  --> tests/ui/cast_size.rs:31:5
    |
 LL |     1usize as i32;
    |     ^^^^^^^^^^^^^
@@ -97,7 +97,7 @@ LL |     1usize as i32;
    = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]`
 
 error: casting `i64` to `isize` may truncate the value on targets with 32-bit wide pointers
-  --> tests/ui/cast_size.rs:26:5
+  --> tests/ui/cast_size.rs:32:5
    |
 LL |     1i64 as isize;
    |     ^^^^^^^^^^^^^
@@ -109,7 +109,7 @@ LL |     isize::try_from(1i64);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers
-  --> tests/ui/cast_size.rs:27:5
+  --> tests/ui/cast_size.rs:33:5
    |
 LL |     1i64 as usize;
    |     ^^^^^^^^^^^^^
@@ -121,7 +121,7 @@ LL |     usize::try_from(1i64);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers
-  --> tests/ui/cast_size.rs:28:5
+  --> tests/ui/cast_size.rs:34:5
    |
 LL |     1u64 as isize;
    |     ^^^^^^^^^^^^^
@@ -133,13 +133,13 @@ LL |     isize::try_from(1u64);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers
-  --> tests/ui/cast_size.rs:28:5
+  --> tests/ui/cast_size.rs:34:5
    |
 LL |     1u64 as isize;
    |     ^^^^^^^^^^^^^
 
 error: casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers
-  --> tests/ui/cast_size.rs:29:5
+  --> tests/ui/cast_size.rs:35:5
    |
 LL |     1u64 as usize;
    |     ^^^^^^^^^^^^^
@@ -151,25 +151,25 @@ LL |     usize::try_from(1u64);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers
-  --> tests/ui/cast_size.rs:30:5
+  --> tests/ui/cast_size.rs:36:5
    |
 LL |     1u32 as isize;
    |     ^^^^^^^^^^^^^
 
 error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast_size.rs:35:5
+  --> tests/ui/cast_size.rs:43:5
    |
 LL |     999_999_999 as f32;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
-  --> tests/ui/cast_size.rs:36:5
+  --> tests/ui/cast_size.rs:44:5
    |
 LL |     9_999_999_999_999_999usize as f64;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: literal out of range for `usize`
-  --> tests/ui/cast_size.rs:36:5
+  --> tests/ui/cast_size.rs:44:5
    |
 LL |     9_999_999_999_999_999usize as f64;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/cast_size.64bit.stderr b/src/tools/clippy/tests/ui/cast_size.64bit.stderr
index 0dc4ca91529..bc37107d80e 100644
--- a/src/tools/clippy/tests/ui/cast_size.64bit.stderr
+++ b/src/tools/clippy/tests/ui/cast_size.64bit.stderr
@@ -12,35 +12,35 @@ help: ... or use `try_from` and handle the error accordingly
 LL |     i8::try_from(1isize);
    |     ~~~~~~~~~~~~~~~~~~~~
 
-error: casting `isize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`isize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
-  --> tests/ui/cast_size.rs:18:5
+error: casting `isize` to `f32` causes a loss of precision (`isize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
+  --> tests/ui/cast_size.rs:21:5
    |
-LL |     x0 as f64;
+LL |     x0 as f32;
    |     ^^^^^^^^^
    |
    = note: `-D clippy::cast-precision-loss` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]`
 
-error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
-  --> tests/ui/cast_size.rs:19:5
+error: casting `usize` to `f32` causes a loss of precision (`usize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
+  --> tests/ui/cast_size.rs:22:5
    |
-LL |     x1 as f64;
+LL |     x1 as f32;
    |     ^^^^^^^^^
 
-error: casting `isize` to `f32` causes a loss of precision (`isize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast_size.rs:20:5
+error: casting `isize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`isize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
+  --> tests/ui/cast_size.rs:23:5
    |
-LL |     x0 as f32;
+LL |     x0 as f64;
    |     ^^^^^^^^^
 
-error: casting `usize` to `f32` causes a loss of precision (`usize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast_size.rs:21:5
+error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
+  --> tests/ui/cast_size.rs:24:5
    |
-LL |     x1 as f32;
+LL |     x1 as f64;
    |     ^^^^^^^^^
 
 error: casting `isize` to `i32` may truncate the value on targets with 64-bit wide pointers
-  --> tests/ui/cast_size.rs:22:5
+  --> tests/ui/cast_size.rs:28:5
    |
 LL |     1isize as i32;
    |     ^^^^^^^^^^^^^
@@ -52,7 +52,7 @@ LL |     i32::try_from(1isize);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `isize` to `u32` may truncate the value on targets with 64-bit wide pointers
-  --> tests/ui/cast_size.rs:23:5
+  --> tests/ui/cast_size.rs:29:5
    |
 LL |     1isize as u32;
    |     ^^^^^^^^^^^^^
@@ -64,7 +64,7 @@ LL |     u32::try_from(1isize);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers
-  --> tests/ui/cast_size.rs:24:5
+  --> tests/ui/cast_size.rs:30:5
    |
 LL |     1usize as u32;
    |     ^^^^^^^^^^^^^
@@ -76,7 +76,7 @@ LL |     u32::try_from(1usize);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers
-  --> tests/ui/cast_size.rs:25:5
+  --> tests/ui/cast_size.rs:31:5
    |
 LL |     1usize as i32;
    |     ^^^^^^^^^^^^^
@@ -88,7 +88,7 @@ LL |     i32::try_from(1usize);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers
-  --> tests/ui/cast_size.rs:25:5
+  --> tests/ui/cast_size.rs:31:5
    |
 LL |     1usize as i32;
    |     ^^^^^^^^^^^^^
@@ -97,7 +97,7 @@ LL |     1usize as i32;
    = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]`
 
 error: casting `i64` to `isize` may truncate the value on targets with 32-bit wide pointers
-  --> tests/ui/cast_size.rs:26:5
+  --> tests/ui/cast_size.rs:32:5
    |
 LL |     1i64 as isize;
    |     ^^^^^^^^^^^^^
@@ -109,7 +109,7 @@ LL |     isize::try_from(1i64);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers
-  --> tests/ui/cast_size.rs:27:5
+  --> tests/ui/cast_size.rs:33:5
    |
 LL |     1i64 as usize;
    |     ^^^^^^^^^^^^^
@@ -121,7 +121,7 @@ LL |     usize::try_from(1i64);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers
-  --> tests/ui/cast_size.rs:28:5
+  --> tests/ui/cast_size.rs:34:5
    |
 LL |     1u64 as isize;
    |     ^^^^^^^^^^^^^
@@ -133,13 +133,13 @@ LL |     isize::try_from(1u64);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers
-  --> tests/ui/cast_size.rs:28:5
+  --> tests/ui/cast_size.rs:34:5
    |
 LL |     1u64 as isize;
    |     ^^^^^^^^^^^^^
 
 error: casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers
-  --> tests/ui/cast_size.rs:29:5
+  --> tests/ui/cast_size.rs:35:5
    |
 LL |     1u64 as usize;
    |     ^^^^^^^^^^^^^
@@ -151,19 +151,19 @@ LL |     usize::try_from(1u64);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers
-  --> tests/ui/cast_size.rs:30:5
+  --> tests/ui/cast_size.rs:36:5
    |
 LL |     1u32 as isize;
    |     ^^^^^^^^^^^^^
 
 error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast_size.rs:35:5
+  --> tests/ui/cast_size.rs:43:5
    |
 LL |     999_999_999 as f32;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
-  --> tests/ui/cast_size.rs:36:5
+  --> tests/ui/cast_size.rs:44:5
    |
 LL |     9_999_999_999_999_999usize as f64;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/cast_size.rs b/src/tools/clippy/tests/ui/cast_size.rs
index d063a70ccdf..d0ed8e57d7a 100644
--- a/src/tools/clippy/tests/ui/cast_size.rs
+++ b/src/tools/clippy/tests/ui/cast_size.rs
@@ -15,10 +15,16 @@ fn main() {
     1isize as i8;
     let x0 = 1isize;
     let x1 = 1usize;
-    x0 as f64;
-    x1 as f64;
+    // FIXME(f16_f128): enable f16 and f128 conversions once const eval supports them
+    // x0 as f16;
+    // x1 as f16;
     x0 as f32;
     x1 as f32;
+    x0 as f64;
+    x1 as f64;
+    // x0 as f128;
+    // x1 as f128;
+
     1isize as i32;
     1isize as u32;
     1usize as u32;
@@ -31,7 +37,10 @@ fn main() {
     1u32 as usize; // Should not trigger any lint
     1i32 as isize; // Neither should this
     1i32 as usize;
+
     // Big integer literal to float
+    // 999_999 as f16;
     999_999_999 as f32;
     9_999_999_999_999_999usize as f64;
+    // 999_999_999_999_999_999_999_999_999_999u128 as f128;
 }
diff --git a/src/tools/clippy/tests/ui/cfg_attr_cargo_clippy.stderr b/src/tools/clippy/tests/ui/cfg_attr_cargo_clippy.stderr
index ddec0e648d1..0a358f1a684 100644
--- a/src/tools/clippy/tests/ui/cfg_attr_cargo_clippy.stderr
+++ b/src/tools/clippy/tests/ui/cfg_attr_cargo_clippy.stderr
@@ -1,13 +1,19 @@
 error: `feature = "cargo-clippy"` was replaced by `clippy`
-  --> tests/ui/cfg_attr_cargo_clippy.rs:5:12
+  --> tests/ui/cfg_attr_cargo_clippy.rs:3:13
    |
-LL | #[cfg_attr(feature = "cargo-clippy", derive(Debug))]
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `clippy`
+LL | #![cfg_attr(feature = "cargo-clippy", doc = "a")]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `clippy`
    |
    = note: `-D clippy::deprecated-clippy-cfg-attr` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::deprecated_clippy_cfg_attr)]`
 
 error: `feature = "cargo-clippy"` was replaced by `clippy`
+  --> tests/ui/cfg_attr_cargo_clippy.rs:5:12
+   |
+LL | #[cfg_attr(feature = "cargo-clippy", derive(Debug))]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `clippy`
+
+error: `feature = "cargo-clippy"` was replaced by `clippy`
   --> tests/ui/cfg_attr_cargo_clippy.rs:6:16
    |
 LL | #[cfg_attr(not(feature = "cargo-clippy"), derive(Debug))]
@@ -37,11 +43,5 @@ error: `feature = "cargo-clippy"` was replaced by `clippy`
 LL | #[cfg(all(feature = "cargo-clippy"))]
    |           ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `clippy`
 
-error: `feature = "cargo-clippy"` was replaced by `clippy`
-  --> tests/ui/cfg_attr_cargo_clippy.rs:3:13
-   |
-LL | #![cfg_attr(feature = "cargo-clippy", doc = "a")]
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `clippy`
-
 error: aborting due to 7 previous errors
 
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 02f80cc52ac..c3c8562edff 100644
--- a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs
+++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs
@@ -1,5 +1,4 @@
 //@no-rustfix: overlapping suggestions
-#![feature(lint_reasons)]
 #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
 #![allow(
     clippy::if_same_then_else,
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 bae62133760..ddd600418af 100644
--- a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr
+++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr
@@ -1,5 +1,5 @@
 error: called `unwrap` on `x` after checking its variant with `is_some`
-  --> tests/ui/checked_unwrap/simple_conditionals.rs:47:9
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:46:9
    |
 LL |     if x.is_some() {
    |     -------------- help: try: `if let Some(..) = x`
@@ -8,13 +8,13 @@ LL |         x.unwrap();
    |         ^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> tests/ui/checked_unwrap/simple_conditionals.rs:3:35
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:2:35
    |
 LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: called `expect` on `x` after checking its variant with `is_some`
-  --> tests/ui/checked_unwrap/simple_conditionals.rs:50:9
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:49:9
    |
 LL |     if x.is_some() {
    |     -------------- help: try: `if let Some(..) = x`
@@ -23,7 +23,7 @@ LL |         x.expect("an error message");
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this call to `unwrap()` will always panic
-  --> tests/ui/checked_unwrap/simple_conditionals.rs:54:9
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:53:9
    |
 LL |     if x.is_some() {
    |        ----------- because of this check
@@ -32,13 +32,13 @@ LL |         x.unwrap();
    |         ^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> tests/ui/checked_unwrap/simple_conditionals.rs:3:9
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:2:9
    |
 LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this call to `expect()` will always panic
-  --> tests/ui/checked_unwrap/simple_conditionals.rs:57:9
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:56:9
    |
 LL |     if x.is_some() {
    |        ----------- because of this check
@@ -47,7 +47,7 @@ LL |         x.expect("an error message");
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this call to `unwrap()` will always panic
-  --> tests/ui/checked_unwrap/simple_conditionals.rs:62:9
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:61:9
    |
 LL |     if x.is_none() {
    |        ----------- because of this check
@@ -56,7 +56,7 @@ LL |         x.unwrap();
    |         ^^^^^^^^^^
 
 error: called `unwrap` on `x` after checking its variant with `is_none`
-  --> tests/ui/checked_unwrap/simple_conditionals.rs:66:9
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:65:9
    |
 LL |     if x.is_none() {
    |     -------------- help: try: `if let Some(..) = x`
@@ -65,7 +65,7 @@ LL |         x.unwrap();
    |         ^^^^^^^^^^
 
 error: called `unwrap` on `x` after checking its variant with `is_some`
-  --> tests/ui/checked_unwrap/simple_conditionals.rs:14:13
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:13:13
    |
 LL |         if $a.is_some() {
    |         --------------- help: try: `if let Some(..) = x`
@@ -79,7 +79,7 @@ LL |     m!(x);
    = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: called `unwrap` on `x` after checking its variant with `is_ok`
-  --> tests/ui/checked_unwrap/simple_conditionals.rs:79:9
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:78:9
    |
 LL |     if x.is_ok() {
    |     ------------ help: try: `if let Ok(..) = x`
@@ -88,7 +88,7 @@ LL |         x.unwrap();
    |         ^^^^^^^^^^
 
 error: called `expect` on `x` after checking its variant with `is_ok`
-  --> tests/ui/checked_unwrap/simple_conditionals.rs:82:9
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:81:9
    |
 LL |     if x.is_ok() {
    |     ------------ help: try: `if let Ok(..) = x`
@@ -97,7 +97,7 @@ LL |         x.expect("an error message");
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this call to `unwrap_err()` will always panic
-  --> tests/ui/checked_unwrap/simple_conditionals.rs:85:9
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:84:9
    |
 LL |     if x.is_ok() {
    |        --------- because of this check
@@ -106,7 +106,7 @@ LL |         x.unwrap_err();
    |         ^^^^^^^^^^^^^^
 
 error: this call to `unwrap()` will always panic
-  --> tests/ui/checked_unwrap/simple_conditionals.rs:89:9
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:88:9
    |
 LL |     if x.is_ok() {
    |        --------- because of this check
@@ -115,7 +115,7 @@ LL |         x.unwrap();
    |         ^^^^^^^^^^
 
 error: this call to `expect()` will always panic
-  --> tests/ui/checked_unwrap/simple_conditionals.rs:92:9
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:91:9
    |
 LL |     if x.is_ok() {
    |        --------- because of this check
@@ -124,7 +124,7 @@ LL |         x.expect("an error message");
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: called `unwrap_err` on `x` after checking its variant with `is_ok`
-  --> tests/ui/checked_unwrap/simple_conditionals.rs:95:9
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:94:9
    |
 LL |     if x.is_ok() {
    |     ------------ help: try: `if let Err(..) = x`
@@ -133,7 +133,7 @@ LL |         x.unwrap_err();
    |         ^^^^^^^^^^^^^^
 
 error: this call to `unwrap()` will always panic
-  --> tests/ui/checked_unwrap/simple_conditionals.rs:100:9
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:99:9
    |
 LL |     if x.is_err() {
    |        ---------- because of this check
@@ -142,7 +142,7 @@ LL |         x.unwrap();
    |         ^^^^^^^^^^
 
 error: called `unwrap_err` on `x` after checking its variant with `is_err`
-  --> tests/ui/checked_unwrap/simple_conditionals.rs:103:9
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:102:9
    |
 LL |     if x.is_err() {
    |     ------------- help: try: `if let Err(..) = x`
@@ -151,7 +151,7 @@ LL |         x.unwrap_err();
    |         ^^^^^^^^^^^^^^
 
 error: called `unwrap` on `x` after checking its variant with `is_err`
-  --> tests/ui/checked_unwrap/simple_conditionals.rs:107:9
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:106:9
    |
 LL |     if x.is_err() {
    |     ------------- help: try: `if let Ok(..) = x`
@@ -160,7 +160,7 @@ LL |         x.unwrap();
    |         ^^^^^^^^^^
 
 error: this call to `unwrap_err()` will always panic
-  --> tests/ui/checked_unwrap/simple_conditionals.rs:110:9
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:109:9
    |
 LL |     if x.is_err() {
    |        ---------- because of this check
@@ -169,7 +169,7 @@ LL |         x.unwrap_err();
    |         ^^^^^^^^^^^^^^
 
 error: called `unwrap` on `option` after checking its variant with `is_some`
-  --> tests/ui/checked_unwrap/simple_conditionals.rs:135:9
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:134:9
    |
 LL |     if option.is_some() {
    |     ------------------- help: try: `if let Some(..) = &option`
@@ -177,7 +177,7 @@ LL |         option.as_ref().unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this call to `unwrap()` will always panic
-  --> tests/ui/checked_unwrap/simple_conditionals.rs:138:9
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:137:9
    |
 LL |     if option.is_some() {
    |        ---------------- because of this check
@@ -186,7 +186,7 @@ LL |         option.as_ref().unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: called `unwrap` on `result` after checking its variant with `is_ok`
-  --> tests/ui/checked_unwrap/simple_conditionals.rs:145:9
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:144:9
    |
 LL |     if result.is_ok() {
    |     ----------------- help: try: `if let Ok(..) = &result`
@@ -194,7 +194,7 @@ LL |         result.as_ref().unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this call to `unwrap()` will always panic
-  --> tests/ui/checked_unwrap/simple_conditionals.rs:148:9
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:147:9
    |
 LL |     if result.is_ok() {
    |        -------------- because of this check
@@ -203,7 +203,7 @@ LL |         result.as_ref().unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: called `unwrap` on `option` after checking its variant with `is_some`
-  --> tests/ui/checked_unwrap/simple_conditionals.rs:154:9
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:153:9
    |
 LL |     if option.is_some() {
    |     ------------------- help: try: `if let Some(..) = &mut option`
@@ -211,7 +211,7 @@ LL |         option.as_mut().unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this call to `unwrap()` will always panic
-  --> tests/ui/checked_unwrap/simple_conditionals.rs:157:9
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:156:9
    |
 LL |     if option.is_some() {
    |        ---------------- because of this check
@@ -220,7 +220,7 @@ LL |         option.as_mut().unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: called `unwrap` on `result` after checking its variant with `is_ok`
-  --> tests/ui/checked_unwrap/simple_conditionals.rs:163:9
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:162:9
    |
 LL |     if result.is_ok() {
    |     ----------------- help: try: `if let Ok(..) = &mut result`
@@ -228,7 +228,7 @@ LL |         result.as_mut().unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this call to `unwrap()` will always panic
-  --> tests/ui/checked_unwrap/simple_conditionals.rs:166:9
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:165:9
    |
 LL |     if result.is_ok() {
    |        -------------- because of this check
diff --git a/src/tools/clippy/tests/ui/copy_iterator.rs b/src/tools/clippy/tests/ui/copy_iterator.rs
index c0e5fc3e446..ea3a4face93 100644
--- a/src/tools/clippy/tests/ui/copy_iterator.rs
+++ b/src/tools/clippy/tests/ui/copy_iterator.rs
@@ -1,4 +1,5 @@
 #![warn(clippy::copy_iterator)]
+#![allow(clippy::manual_inspect)]
 
 #[derive(Copy, Clone)]
 struct Countdown(u8);
diff --git a/src/tools/clippy/tests/ui/copy_iterator.stderr b/src/tools/clippy/tests/ui/copy_iterator.stderr
index 533bddaadb5..990b1ce628d 100644
--- a/src/tools/clippy/tests/ui/copy_iterator.stderr
+++ b/src/tools/clippy/tests/ui/copy_iterator.stderr
@@ -1,5 +1,5 @@
 error: you are implementing `Iterator` on a `Copy` type
-  --> tests/ui/copy_iterator.rs:6:1
+  --> tests/ui/copy_iterator.rs:7:1
    |
 LL | / impl Iterator for Countdown {
 LL | |
diff --git a/src/tools/clippy/tests/ui/crashes/ice-12284.rs b/src/tools/clippy/tests/ui/crashes/ice-12284.rs
new file mode 100644
index 00000000000..8d1dbface8e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-12284.rs
@@ -0,0 +1,10 @@
+#![allow(incomplete_features)]
+#![feature(unnamed_fields)]
+
+#[repr(C)]
+struct Foo {
+    _: struct {
+    },
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr
index 86667701da0..7d3c3f7c918 100644
--- a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr
+++ b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr
@@ -86,7 +86,6 @@ LL |     dbg!();
 help: remove the invocation before committing it to a version control system
    |
 LL -     dbg!();
-LL +     
    |
 
 error: the `dbg!` macro is intended as a debugging tool
@@ -146,7 +145,6 @@ LL |     expand_to_dbg!();
 help: remove the invocation before committing it to a version control system
    |
 LL -             dbg!();
-LL +             
    |
 
 error: the `dbg!` macro is intended as a debugging tool
diff --git a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.stderr b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.stderr
index d21595c2fcd..16e51f4742e 100644
--- a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.stderr
+++ b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.stderr
@@ -9,7 +9,6 @@ LL |     dbg!();
 help: remove the invocation before committing it to a version control system
    |
 LL -     dbg!();
-LL +     
    |
 
 error: the `dbg!` macro is intended as a debugging tool
diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed
index e7038082c08..f28ae04fd0a 100644
--- a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed
+++ b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed
@@ -1,6 +1,5 @@
 //@aux-build:proc_macros.rs
 
-#![feature(lint_reasons)]
 #![warn(clippy::default_numeric_fallback)]
 #![allow(
     unused,
diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs
index d8eeda70491..78a5006444e 100644
--- a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs
+++ b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs
@@ -1,6 +1,5 @@
 //@aux-build:proc_macros.rs
 
-#![feature(lint_reasons)]
 #![warn(clippy::default_numeric_fallback)]
 #![allow(
     unused,
diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr
index 9961a3669ef..67ab923ecf5 100644
--- a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr
+++ b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr
@@ -1,5 +1,5 @@
 error: default numeric fallback might occur
-  --> tests/ui/default_numeric_fallback_i32.rs:21:17
+  --> tests/ui/default_numeric_fallback_i32.rs:20:17
    |
 LL |         let x = 22;
    |                 ^^ help: consider adding suffix: `22_i32`
@@ -8,145 +8,145 @@ LL |         let x = 22;
    = help: to override `-D warnings` add `#[allow(clippy::default_numeric_fallback)]`
 
 error: default numeric fallback might occur
-  --> tests/ui/default_numeric_fallback_i32.rs:22:18
+  --> tests/ui/default_numeric_fallback_i32.rs:21:18
    |
 LL |         let x = [1, 2, 3];
    |                  ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> tests/ui/default_numeric_fallback_i32.rs:22:21
+  --> tests/ui/default_numeric_fallback_i32.rs:21:21
    |
 LL |         let x = [1, 2, 3];
    |                     ^ help: consider adding suffix: `2_i32`
 
 error: default numeric fallback might occur
-  --> tests/ui/default_numeric_fallback_i32.rs:22:24
+  --> tests/ui/default_numeric_fallback_i32.rs:21:24
    |
 LL |         let x = [1, 2, 3];
    |                        ^ help: consider adding suffix: `3_i32`
 
 error: default numeric fallback might occur
-  --> tests/ui/default_numeric_fallback_i32.rs:23:28
+  --> tests/ui/default_numeric_fallback_i32.rs:22:28
    |
 LL |         let x = if true { (1, 2) } else { (3, 4) };
    |                            ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> tests/ui/default_numeric_fallback_i32.rs:23:31
+  --> tests/ui/default_numeric_fallback_i32.rs:22:31
    |
 LL |         let x = if true { (1, 2) } else { (3, 4) };
    |                               ^ help: consider adding suffix: `2_i32`
 
 error: default numeric fallback might occur
-  --> tests/ui/default_numeric_fallback_i32.rs:23:44
+  --> tests/ui/default_numeric_fallback_i32.rs:22:44
    |
 LL |         let x = if true { (1, 2) } else { (3, 4) };
    |                                            ^ help: consider adding suffix: `3_i32`
 
 error: default numeric fallback might occur
-  --> tests/ui/default_numeric_fallback_i32.rs:23:47
+  --> tests/ui/default_numeric_fallback_i32.rs:22:47
    |
 LL |         let x = if true { (1, 2) } else { (3, 4) };
    |                                               ^ help: consider adding suffix: `4_i32`
 
 error: default numeric fallback might occur
-  --> tests/ui/default_numeric_fallback_i32.rs:24:23
+  --> tests/ui/default_numeric_fallback_i32.rs:23:23
    |
 LL |         let x = match 1 {
    |                       ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> tests/ui/default_numeric_fallback_i32.rs:25:13
+  --> tests/ui/default_numeric_fallback_i32.rs:24:13
    |
 LL |             1 => 1,
    |             ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> tests/ui/default_numeric_fallback_i32.rs:25:18
+  --> tests/ui/default_numeric_fallback_i32.rs:24:18
    |
 LL |             1 => 1,
    |                  ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> tests/ui/default_numeric_fallback_i32.rs:26:18
+  --> tests/ui/default_numeric_fallback_i32.rs:25:18
    |
 LL |             _ => 2,
    |                  ^ help: consider adding suffix: `2_i32`
 
 error: default numeric fallback might occur
-  --> tests/ui/default_numeric_fallback_i32.rs:45:21
+  --> tests/ui/default_numeric_fallback_i32.rs:44:21
    |
 LL |             let y = 1;
    |                     ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> tests/ui/default_numeric_fallback_i32.rs:53:21
+  --> tests/ui/default_numeric_fallback_i32.rs:52:21
    |
 LL |             let y = 1;
    |                     ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> tests/ui/default_numeric_fallback_i32.rs:59:21
+  --> tests/ui/default_numeric_fallback_i32.rs:58:21
    |
 LL |             let y = 1;
    |                     ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> tests/ui/default_numeric_fallback_i32.rs:67:21
+  --> tests/ui/default_numeric_fallback_i32.rs:66:21
    |
 LL |             let y = 1;
    |                     ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> tests/ui/default_numeric_fallback_i32.rs:83:27
+  --> tests/ui/default_numeric_fallback_i32.rs:82:27
    |
 LL |         let f = || -> _ { 1 };
    |                           ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> tests/ui/default_numeric_fallback_i32.rs:87:29
+  --> tests/ui/default_numeric_fallback_i32.rs:86:29
    |
 LL |         let f = || -> i32 { 1 };
    |                             ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> tests/ui/default_numeric_fallback_i32.rs:101:21
+  --> tests/ui/default_numeric_fallback_i32.rs:100:21
    |
 LL |         generic_arg(1);
    |                     ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> tests/ui/default_numeric_fallback_i32.rs:104:32
+  --> tests/ui/default_numeric_fallback_i32.rs:103:32
    |
 LL |         let x: _ = generic_arg(1);
    |                                ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> tests/ui/default_numeric_fallback_i32.rs:122:28
+  --> tests/ui/default_numeric_fallback_i32.rs:121:28
    |
 LL |         GenericStruct { x: 1 };
    |                            ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> tests/ui/default_numeric_fallback_i32.rs:125:36
+  --> tests/ui/default_numeric_fallback_i32.rs:124:36
    |
 LL |         let _ = GenericStruct { x: 1 };
    |                                    ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> tests/ui/default_numeric_fallback_i32.rs:143:24
+  --> tests/ui/default_numeric_fallback_i32.rs:142:24
    |
 LL |         GenericEnum::X(1);
    |                        ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> tests/ui/default_numeric_fallback_i32.rs:163:23
+  --> tests/ui/default_numeric_fallback_i32.rs:162:23
    |
 LL |         s.generic_arg(1);
    |                       ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> tests/ui/default_numeric_fallback_i32.rs:173:25
+  --> tests/ui/default_numeric_fallback_i32.rs:172:25
    |
 LL |         inline!(let x = 22;);
    |                         ^^ help: consider adding suffix: `22_i32`
@@ -154,19 +154,19 @@ LL |         inline!(let x = 22;);
    = note: this error originates in the macro `__inline_mac_fn_internal` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: default numeric fallback might occur
-  --> tests/ui/default_numeric_fallback_i32.rs:215:29
+  --> tests/ui/default_numeric_fallback_i32.rs:214:29
    |
 LL |         let data_i32 = vec![1, 2, 3];
    |                             ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> tests/ui/default_numeric_fallback_i32.rs:215:32
+  --> tests/ui/default_numeric_fallback_i32.rs:214:32
    |
 LL |         let data_i32 = vec![1, 2, 3];
    |                                ^ help: consider adding suffix: `2_i32`
 
 error: default numeric fallback might occur
-  --> tests/ui/default_numeric_fallback_i32.rs:215:35
+  --> tests/ui/default_numeric_fallback_i32.rs:214:35
    |
 LL |         let data_i32 = vec![1, 2, 3];
    |                                   ^ help: consider adding suffix: `3_i32`
diff --git a/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.fixed b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.fixed
index eb93eb8e8ed..e4a33193a1a 100644
--- a/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.fixed
+++ b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.fixed
@@ -1,4 +1,3 @@
-#![feature(lint_reasons)]
 #![allow(unused)]
 #![warn(clippy::derive_partial_eq_without_eq)]
 
diff --git a/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.rs b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.rs
index 42dc435bdd5..a418b38e349 100644
--- a/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.rs
+++ b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.rs
@@ -1,4 +1,3 @@
-#![feature(lint_reasons)]
 #![allow(unused)]
 #![warn(clippy::derive_partial_eq_without_eq)]
 
diff --git a/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.stderr b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.stderr
index 29cd7da6b77..7436114fadb 100644
--- a/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.stderr
+++ b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.stderr
@@ -1,5 +1,5 @@
 error: you are deriving `PartialEq` and can implement `Eq`
-  --> tests/ui/derive_partial_eq_without_eq.rs:12:17
+  --> tests/ui/derive_partial_eq_without_eq.rs:11:17
    |
 LL | #[derive(Debug, PartialEq)]
    |                 ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq`
@@ -8,73 +8,73 @@ LL | #[derive(Debug, PartialEq)]
    = help: to override `-D warnings` add `#[allow(clippy::derive_partial_eq_without_eq)]`
 
 error: you are deriving `PartialEq` and can implement `Eq`
-  --> tests/ui/derive_partial_eq_without_eq.rs:70:10
+  --> tests/ui/derive_partial_eq_without_eq.rs:69:10
    |
 LL | #[derive(PartialEq)]
    |          ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq`
 
 error: you are deriving `PartialEq` and can implement `Eq`
-  --> tests/ui/derive_partial_eq_without_eq.rs:76:10
+  --> tests/ui/derive_partial_eq_without_eq.rs:75:10
    |
 LL | #[derive(PartialEq)]
    |          ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq`
 
 error: you are deriving `PartialEq` and can implement `Eq`
-  --> tests/ui/derive_partial_eq_without_eq.rs:82:10
+  --> tests/ui/derive_partial_eq_without_eq.rs:81:10
    |
 LL | #[derive(PartialEq)]
    |          ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq`
 
 error: you are deriving `PartialEq` and can implement `Eq`
-  --> tests/ui/derive_partial_eq_without_eq.rs:85:10
+  --> tests/ui/derive_partial_eq_without_eq.rs:84:10
    |
 LL | #[derive(PartialEq)]
    |          ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq`
 
 error: you are deriving `PartialEq` and can implement `Eq`
-  --> tests/ui/derive_partial_eq_without_eq.rs:91:10
+  --> tests/ui/derive_partial_eq_without_eq.rs:90:10
    |
 LL | #[derive(PartialEq)]
    |          ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq`
 
 error: you are deriving `PartialEq` and can implement `Eq`
-  --> tests/ui/derive_partial_eq_without_eq.rs:97:10
+  --> tests/ui/derive_partial_eq_without_eq.rs:96:10
    |
 LL | #[derive(PartialEq)]
    |          ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq`
 
 error: you are deriving `PartialEq` and can implement `Eq`
-  --> tests/ui/derive_partial_eq_without_eq.rs:110:17
+  --> tests/ui/derive_partial_eq_without_eq.rs:109:17
    |
 LL | #[derive(Debug, PartialEq, Clone)]
    |                 ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq`
 
 error: you are deriving `PartialEq` and can implement `Eq`
-  --> tests/ui/derive_partial_eq_without_eq.rs:113:10
+  --> tests/ui/derive_partial_eq_without_eq.rs:112:10
    |
 LL | #[derive(PartialEq)]
    |          ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq`
 
 error: you are deriving `PartialEq` and can implement `Eq`
-  --> tests/ui/derive_partial_eq_without_eq.rs:120:14
+  --> tests/ui/derive_partial_eq_without_eq.rs:119:14
    |
 LL |     #[derive(PartialEq)]
    |              ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq`
 
 error: you are deriving `PartialEq` and can implement `Eq`
-  --> tests/ui/derive_partial_eq_without_eq.rs:123:14
+  --> tests/ui/derive_partial_eq_without_eq.rs:122:14
    |
 LL |     #[derive(PartialEq)]
    |              ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq`
 
 error: you are deriving `PartialEq` and can implement `Eq`
-  --> tests/ui/derive_partial_eq_without_eq.rs:183:14
+  --> tests/ui/derive_partial_eq_without_eq.rs:182:14
    |
 LL |     #[derive(PartialEq)]
    |              ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq`
 
 error: you are deriving `PartialEq` and can implement `Eq`
-  --> tests/ui/derive_partial_eq_without_eq.rs:191:14
+  --> tests/ui/derive_partial_eq_without_eq.rs:190:14
    |
 LL |     #[derive(PartialEq)]
    |              ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq`
diff --git a/src/tools/clippy/tests/ui/endian_bytes.rs b/src/tools/clippy/tests/ui/endian_bytes.rs
index 6bf014fc809..580fc2fc24d 100644
--- a/src/tools/clippy/tests/ui/endian_bytes.rs
+++ b/src/tools/clippy/tests/ui/endian_bytes.rs
@@ -2,6 +2,8 @@
 #![allow(clippy::diverging_sub_expression)]
 #![no_main]
 
+// FIXME(f16_f128): add these types when `{to_from}_*_bytes` are available
+
 macro_rules! fn_body {
     () => {
         2u8.to_ne_bytes();
diff --git a/src/tools/clippy/tests/ui/endian_bytes.stderr b/src/tools/clippy/tests/ui/endian_bytes.stderr
index 3fc26dcab88..fd19ec45872 100644
--- a/src/tools/clippy/tests/ui/endian_bytes.stderr
+++ b/src/tools/clippy/tests/ui/endian_bytes.stderr
@@ -1,5 +1,5 @@
 error: usage of the `u8::to_ne_bytes` method
-  --> tests/ui/endian_bytes.rs:7:9
+  --> tests/ui/endian_bytes.rs:9:9
    |
 LL |         2u8.to_ne_bytes();
    |         ^^^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ LL | fn host() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `i8::to_ne_bytes` method
-  --> tests/ui/endian_bytes.rs:8:9
+  --> tests/ui/endian_bytes.rs:10:9
    |
 LL |         2i8.to_ne_bytes();
    |         ^^^^^^^^^^^^^^^^^
@@ -25,7 +25,7 @@ LL | fn host() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `u16::to_ne_bytes` method
-  --> tests/ui/endian_bytes.rs:9:9
+  --> tests/ui/endian_bytes.rs:11:9
    |
 LL |         2u16.to_ne_bytes();
    |         ^^^^^^^^^^^^^^^^^^
@@ -37,7 +37,7 @@ LL | fn host() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `i16::to_ne_bytes` method
-  --> tests/ui/endian_bytes.rs:10:9
+  --> tests/ui/endian_bytes.rs:12:9
    |
 LL |         2i16.to_ne_bytes();
    |         ^^^^^^^^^^^^^^^^^^
@@ -49,7 +49,7 @@ LL | fn host() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `u32::to_ne_bytes` method
-  --> tests/ui/endian_bytes.rs:11:9
+  --> tests/ui/endian_bytes.rs:13:9
    |
 LL |         2u32.to_ne_bytes();
    |         ^^^^^^^^^^^^^^^^^^
@@ -61,7 +61,7 @@ LL | fn host() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `i32::to_ne_bytes` method
-  --> tests/ui/endian_bytes.rs:12:9
+  --> tests/ui/endian_bytes.rs:14:9
    |
 LL |         2i32.to_ne_bytes();
    |         ^^^^^^^^^^^^^^^^^^
@@ -73,7 +73,7 @@ LL | fn host() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `u64::to_ne_bytes` method
-  --> tests/ui/endian_bytes.rs:13:9
+  --> tests/ui/endian_bytes.rs:15:9
    |
 LL |         2u64.to_ne_bytes();
    |         ^^^^^^^^^^^^^^^^^^
@@ -85,7 +85,7 @@ LL | fn host() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `i64::to_ne_bytes` method
-  --> tests/ui/endian_bytes.rs:14:9
+  --> tests/ui/endian_bytes.rs:16:9
    |
 LL |         2i64.to_ne_bytes();
    |         ^^^^^^^^^^^^^^^^^^
@@ -97,7 +97,7 @@ LL | fn host() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `u128::to_ne_bytes` method
-  --> tests/ui/endian_bytes.rs:15:9
+  --> tests/ui/endian_bytes.rs:17:9
    |
 LL |         2u128.to_ne_bytes();
    |         ^^^^^^^^^^^^^^^^^^^
@@ -109,7 +109,7 @@ LL | fn host() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `i128::to_ne_bytes` method
-  --> tests/ui/endian_bytes.rs:16:9
+  --> tests/ui/endian_bytes.rs:18:9
    |
 LL |         2i128.to_ne_bytes();
    |         ^^^^^^^^^^^^^^^^^^^
@@ -121,7 +121,7 @@ LL | fn host() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `f32::to_ne_bytes` method
-  --> tests/ui/endian_bytes.rs:17:9
+  --> tests/ui/endian_bytes.rs:19:9
    |
 LL |         2.0f32.to_ne_bytes();
    |         ^^^^^^^^^^^^^^^^^^^^
@@ -133,7 +133,7 @@ LL | fn host() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `f64::to_ne_bytes` method
-  --> tests/ui/endian_bytes.rs:18:9
+  --> tests/ui/endian_bytes.rs:20:9
    |
 LL |         2.0f64.to_ne_bytes();
    |         ^^^^^^^^^^^^^^^^^^^^
@@ -145,7 +145,7 @@ LL | fn host() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `usize::to_ne_bytes` method
-  --> tests/ui/endian_bytes.rs:19:9
+  --> tests/ui/endian_bytes.rs:21:9
    |
 LL |         2usize.to_ne_bytes();
    |         ^^^^^^^^^^^^^^^^^^^^
@@ -157,7 +157,7 @@ LL | fn host() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `isize::to_ne_bytes` method
-  --> tests/ui/endian_bytes.rs:20:9
+  --> tests/ui/endian_bytes.rs:22:9
    |
 LL |         2isize.to_ne_bytes();
    |         ^^^^^^^^^^^^^^^^^^^^
@@ -169,7 +169,7 @@ LL | fn host() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `u8::from_ne_bytes`
-  --> tests/ui/endian_bytes.rs:21:9
+  --> tests/ui/endian_bytes.rs:23:9
    |
 LL |         u8::from_ne_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -181,7 +181,7 @@ LL | fn host() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `i8::from_ne_bytes`
-  --> tests/ui/endian_bytes.rs:22:9
+  --> tests/ui/endian_bytes.rs:24:9
    |
 LL |         i8::from_ne_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -193,7 +193,7 @@ LL | fn host() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `u16::from_ne_bytes`
-  --> tests/ui/endian_bytes.rs:23:9
+  --> tests/ui/endian_bytes.rs:25:9
    |
 LL |         u16::from_ne_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -205,7 +205,7 @@ LL | fn host() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `i16::from_ne_bytes`
-  --> tests/ui/endian_bytes.rs:24:9
+  --> tests/ui/endian_bytes.rs:26:9
    |
 LL |         i16::from_ne_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -217,7 +217,7 @@ LL | fn host() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `u32::from_ne_bytes`
-  --> tests/ui/endian_bytes.rs:25:9
+  --> tests/ui/endian_bytes.rs:27:9
    |
 LL |         u32::from_ne_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -229,7 +229,7 @@ LL | fn host() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `i32::from_ne_bytes`
-  --> tests/ui/endian_bytes.rs:26:9
+  --> tests/ui/endian_bytes.rs:28:9
    |
 LL |         i32::from_ne_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -241,7 +241,7 @@ LL | fn host() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `u64::from_ne_bytes`
-  --> tests/ui/endian_bytes.rs:27:9
+  --> tests/ui/endian_bytes.rs:29:9
    |
 LL |         u64::from_ne_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -253,7 +253,7 @@ LL | fn host() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `i64::from_ne_bytes`
-  --> tests/ui/endian_bytes.rs:28:9
+  --> tests/ui/endian_bytes.rs:30:9
    |
 LL |         i64::from_ne_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -265,7 +265,7 @@ LL | fn host() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `u128::from_ne_bytes`
-  --> tests/ui/endian_bytes.rs:29:9
+  --> tests/ui/endian_bytes.rs:31:9
    |
 LL |         u128::from_ne_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -277,7 +277,7 @@ LL | fn host() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `i128::from_ne_bytes`
-  --> tests/ui/endian_bytes.rs:30:9
+  --> tests/ui/endian_bytes.rs:32:9
    |
 LL |         i128::from_ne_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -289,7 +289,7 @@ LL | fn host() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `usize::from_ne_bytes`
-  --> tests/ui/endian_bytes.rs:31:9
+  --> tests/ui/endian_bytes.rs:33:9
    |
 LL |         usize::from_ne_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -301,7 +301,7 @@ LL | fn host() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `isize::from_ne_bytes`
-  --> tests/ui/endian_bytes.rs:32:9
+  --> tests/ui/endian_bytes.rs:34:9
    |
 LL |         isize::from_ne_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -313,7 +313,7 @@ LL | fn host() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `f32::from_ne_bytes`
-  --> tests/ui/endian_bytes.rs:33:9
+  --> tests/ui/endian_bytes.rs:35:9
    |
 LL |         f32::from_ne_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -325,7 +325,7 @@ LL | fn host() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `f64::from_ne_bytes`
-  --> tests/ui/endian_bytes.rs:34:9
+  --> tests/ui/endian_bytes.rs:36:9
    |
 LL |         f64::from_ne_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -337,7 +337,7 @@ LL | fn host() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `u8::to_le_bytes` method
-  --> tests/ui/endian_bytes.rs:36:9
+  --> tests/ui/endian_bytes.rs:38:9
    |
 LL |         2u8.to_le_bytes();
    |         ^^^^^^^^^^^^^^^^^
@@ -351,7 +351,7 @@ LL | fn little() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `i8::to_le_bytes` method
-  --> tests/ui/endian_bytes.rs:37:9
+  --> tests/ui/endian_bytes.rs:39:9
    |
 LL |         2i8.to_le_bytes();
    |         ^^^^^^^^^^^^^^^^^
@@ -363,7 +363,7 @@ LL | fn little() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `u16::to_le_bytes` method
-  --> tests/ui/endian_bytes.rs:38:9
+  --> tests/ui/endian_bytes.rs:40:9
    |
 LL |         2u16.to_le_bytes();
    |         ^^^^^^^^^^^^^^^^^^
@@ -375,7 +375,7 @@ LL | fn little() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `i16::to_le_bytes` method
-  --> tests/ui/endian_bytes.rs:39:9
+  --> tests/ui/endian_bytes.rs:41:9
    |
 LL |         2i16.to_le_bytes();
    |         ^^^^^^^^^^^^^^^^^^
@@ -387,7 +387,7 @@ LL | fn little() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `u32::to_le_bytes` method
-  --> tests/ui/endian_bytes.rs:40:9
+  --> tests/ui/endian_bytes.rs:42:9
    |
 LL |         2u32.to_le_bytes();
    |         ^^^^^^^^^^^^^^^^^^
@@ -399,7 +399,7 @@ LL | fn little() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `i32::to_le_bytes` method
-  --> tests/ui/endian_bytes.rs:41:9
+  --> tests/ui/endian_bytes.rs:43:9
    |
 LL |         2i32.to_le_bytes();
    |         ^^^^^^^^^^^^^^^^^^
@@ -411,7 +411,7 @@ LL | fn little() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `u64::to_le_bytes` method
-  --> tests/ui/endian_bytes.rs:42:9
+  --> tests/ui/endian_bytes.rs:44:9
    |
 LL |         2u64.to_le_bytes();
    |         ^^^^^^^^^^^^^^^^^^
@@ -423,7 +423,7 @@ LL | fn little() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `i64::to_le_bytes` method
-  --> tests/ui/endian_bytes.rs:43:9
+  --> tests/ui/endian_bytes.rs:45:9
    |
 LL |         2i64.to_le_bytes();
    |         ^^^^^^^^^^^^^^^^^^
@@ -435,7 +435,7 @@ LL | fn little() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `u128::to_le_bytes` method
-  --> tests/ui/endian_bytes.rs:44:9
+  --> tests/ui/endian_bytes.rs:46:9
    |
 LL |         2u128.to_le_bytes();
    |         ^^^^^^^^^^^^^^^^^^^
@@ -447,7 +447,7 @@ LL | fn little() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `i128::to_le_bytes` method
-  --> tests/ui/endian_bytes.rs:45:9
+  --> tests/ui/endian_bytes.rs:47:9
    |
 LL |         2i128.to_le_bytes();
    |         ^^^^^^^^^^^^^^^^^^^
@@ -459,7 +459,7 @@ LL | fn little() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `f32::to_le_bytes` method
-  --> tests/ui/endian_bytes.rs:46:9
+  --> tests/ui/endian_bytes.rs:48:9
    |
 LL |         2.0f32.to_le_bytes();
    |         ^^^^^^^^^^^^^^^^^^^^
@@ -471,7 +471,7 @@ LL | fn little() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `f64::to_le_bytes` method
-  --> tests/ui/endian_bytes.rs:47:9
+  --> tests/ui/endian_bytes.rs:49:9
    |
 LL |         2.0f64.to_le_bytes();
    |         ^^^^^^^^^^^^^^^^^^^^
@@ -483,7 +483,7 @@ LL | fn little() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `usize::to_le_bytes` method
-  --> tests/ui/endian_bytes.rs:48:9
+  --> tests/ui/endian_bytes.rs:50:9
    |
 LL |         2usize.to_le_bytes();
    |         ^^^^^^^^^^^^^^^^^^^^
@@ -495,7 +495,7 @@ LL | fn little() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `isize::to_le_bytes` method
-  --> tests/ui/endian_bytes.rs:49:9
+  --> tests/ui/endian_bytes.rs:51:9
    |
 LL |         2isize.to_le_bytes();
    |         ^^^^^^^^^^^^^^^^^^^^
@@ -507,7 +507,7 @@ LL | fn little() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `u8::from_le_bytes`
-  --> tests/ui/endian_bytes.rs:50:9
+  --> tests/ui/endian_bytes.rs:52:9
    |
 LL |         u8::from_le_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -519,7 +519,7 @@ LL | fn little() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `i8::from_le_bytes`
-  --> tests/ui/endian_bytes.rs:51:9
+  --> tests/ui/endian_bytes.rs:53:9
    |
 LL |         i8::from_le_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -531,7 +531,7 @@ LL | fn little() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `u16::from_le_bytes`
-  --> tests/ui/endian_bytes.rs:52:9
+  --> tests/ui/endian_bytes.rs:54:9
    |
 LL |         u16::from_le_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -543,7 +543,7 @@ LL | fn little() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `i16::from_le_bytes`
-  --> tests/ui/endian_bytes.rs:53:9
+  --> tests/ui/endian_bytes.rs:55:9
    |
 LL |         i16::from_le_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -555,7 +555,7 @@ LL | fn little() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `u32::from_le_bytes`
-  --> tests/ui/endian_bytes.rs:54:9
+  --> tests/ui/endian_bytes.rs:56:9
    |
 LL |         u32::from_le_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -567,7 +567,7 @@ LL | fn little() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `i32::from_le_bytes`
-  --> tests/ui/endian_bytes.rs:55:9
+  --> tests/ui/endian_bytes.rs:57:9
    |
 LL |         i32::from_le_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -579,7 +579,7 @@ LL | fn little() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `u64::from_le_bytes`
-  --> tests/ui/endian_bytes.rs:56:9
+  --> tests/ui/endian_bytes.rs:58:9
    |
 LL |         u64::from_le_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -591,7 +591,7 @@ LL | fn little() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `i64::from_le_bytes`
-  --> tests/ui/endian_bytes.rs:57:9
+  --> tests/ui/endian_bytes.rs:59:9
    |
 LL |         i64::from_le_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -603,7 +603,7 @@ LL | fn little() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `u128::from_le_bytes`
-  --> tests/ui/endian_bytes.rs:58:9
+  --> tests/ui/endian_bytes.rs:60:9
    |
 LL |         u128::from_le_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -615,7 +615,7 @@ LL | fn little() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `i128::from_le_bytes`
-  --> tests/ui/endian_bytes.rs:59:9
+  --> tests/ui/endian_bytes.rs:61:9
    |
 LL |         i128::from_le_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -627,7 +627,7 @@ LL | fn little() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `usize::from_le_bytes`
-  --> tests/ui/endian_bytes.rs:60:9
+  --> tests/ui/endian_bytes.rs:62:9
    |
 LL |         usize::from_le_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -639,7 +639,7 @@ LL | fn little() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `isize::from_le_bytes`
-  --> tests/ui/endian_bytes.rs:61:9
+  --> tests/ui/endian_bytes.rs:63:9
    |
 LL |         isize::from_le_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -651,7 +651,7 @@ LL | fn little() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `f32::from_le_bytes`
-  --> tests/ui/endian_bytes.rs:62:9
+  --> tests/ui/endian_bytes.rs:64:9
    |
 LL |         f32::from_le_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -663,7 +663,7 @@ LL | fn little() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `f64::from_le_bytes`
-  --> tests/ui/endian_bytes.rs:63:9
+  --> tests/ui/endian_bytes.rs:65:9
    |
 LL |         f64::from_le_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -675,7 +675,7 @@ LL | fn little() { fn_body!(); }
    = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `u8::to_ne_bytes` method
-  --> tests/ui/endian_bytes.rs:70:9
+  --> tests/ui/endian_bytes.rs:72:9
    |
 LL |         2u8.to_ne_bytes();
    |         ^^^^^^^^^^^^^^^^^
@@ -687,7 +687,7 @@ LL | fn host_encourage_little() { fn_body_smol!(); }
    = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `u8::from_ne_bytes`
-  --> tests/ui/endian_bytes.rs:71:9
+  --> tests/ui/endian_bytes.rs:73:9
    |
 LL |         u8::from_ne_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -699,7 +699,7 @@ LL | fn host_encourage_little() { fn_body_smol!(); }
    = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `u8::to_be_bytes` method
-  --> tests/ui/endian_bytes.rs:76:9
+  --> tests/ui/endian_bytes.rs:78:9
    |
 LL |         2u8.to_be_bytes();
    |         ^^^^^^^^^^^^^^^^^
@@ -713,7 +713,7 @@ LL | fn host_encourage_little() { fn_body_smol!(); }
    = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `u8::from_be_bytes`
-  --> tests/ui/endian_bytes.rs:77:9
+  --> tests/ui/endian_bytes.rs:79:9
    |
 LL |         u8::from_be_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -725,7 +725,7 @@ LL | fn host_encourage_little() { fn_body_smol!(); }
    = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `u8::to_ne_bytes` method
-  --> tests/ui/endian_bytes.rs:70:9
+  --> tests/ui/endian_bytes.rs:72:9
    |
 LL |         2u8.to_ne_bytes();
    |         ^^^^^^^^^^^^^^^^^
@@ -737,7 +737,7 @@ LL | fn host_encourage_big() { fn_body_smol!(); }
    = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `u8::from_ne_bytes`
-  --> tests/ui/endian_bytes.rs:71:9
+  --> tests/ui/endian_bytes.rs:73:9
    |
 LL |         u8::from_ne_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -749,7 +749,7 @@ LL | fn host_encourage_big() { fn_body_smol!(); }
    = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `u8::to_le_bytes` method
-  --> tests/ui/endian_bytes.rs:73:9
+  --> tests/ui/endian_bytes.rs:75:9
    |
 LL |         2u8.to_le_bytes();
    |         ^^^^^^^^^^^^^^^^^
@@ -761,7 +761,7 @@ LL | fn host_encourage_big() { fn_body_smol!(); }
    = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `u8::from_le_bytes`
-  --> tests/ui/endian_bytes.rs:74:9
+  --> tests/ui/endian_bytes.rs:76:9
    |
 LL |         u8::from_le_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -773,7 +773,7 @@ LL | fn host_encourage_big() { fn_body_smol!(); }
    = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `u8::to_ne_bytes` method
-  --> tests/ui/endian_bytes.rs:70:9
+  --> tests/ui/endian_bytes.rs:72:9
    |
 LL |         2u8.to_ne_bytes();
    |         ^^^^^^^^^^^^^^^^^
@@ -784,7 +784,7 @@ LL | fn no_help() { fn_body_smol!(); }
    = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `u8::from_ne_bytes`
-  --> tests/ui/endian_bytes.rs:71:9
+  --> tests/ui/endian_bytes.rs:73:9
    |
 LL |         u8::from_ne_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -795,7 +795,7 @@ LL | fn no_help() { fn_body_smol!(); }
    = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `u8::to_le_bytes` method
-  --> tests/ui/endian_bytes.rs:73:9
+  --> tests/ui/endian_bytes.rs:75:9
    |
 LL |         2u8.to_le_bytes();
    |         ^^^^^^^^^^^^^^^^^
@@ -806,7 +806,7 @@ LL | fn no_help() { fn_body_smol!(); }
    = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `u8::from_le_bytes`
-  --> tests/ui/endian_bytes.rs:74:9
+  --> tests/ui/endian_bytes.rs:76:9
    |
 LL |         u8::from_le_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -817,7 +817,7 @@ LL | fn no_help() { fn_body_smol!(); }
    = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `u8::to_be_bytes` method
-  --> tests/ui/endian_bytes.rs:76:9
+  --> tests/ui/endian_bytes.rs:78:9
    |
 LL |         2u8.to_be_bytes();
    |         ^^^^^^^^^^^^^^^^^
@@ -828,7 +828,7 @@ LL | fn no_help() { fn_body_smol!(); }
    = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `u8::from_be_bytes`
-  --> tests/ui/endian_bytes.rs:77:9
+  --> tests/ui/endian_bytes.rs:79:9
    |
 LL |         u8::from_be_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -839,7 +839,7 @@ LL | fn no_help() { fn_body_smol!(); }
    = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `u8::to_le_bytes` method
-  --> tests/ui/endian_bytes.rs:73:9
+  --> tests/ui/endian_bytes.rs:75:9
    |
 LL |         2u8.to_le_bytes();
    |         ^^^^^^^^^^^^^^^^^
@@ -851,7 +851,7 @@ LL | fn little_encourage_host() { fn_body_smol!(); }
    = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `u8::from_le_bytes`
-  --> tests/ui/endian_bytes.rs:74:9
+  --> tests/ui/endian_bytes.rs:76:9
    |
 LL |         u8::from_le_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -863,7 +863,7 @@ LL | fn little_encourage_host() { fn_body_smol!(); }
    = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `u8::to_be_bytes` method
-  --> tests/ui/endian_bytes.rs:76:9
+  --> tests/ui/endian_bytes.rs:78:9
    |
 LL |         2u8.to_be_bytes();
    |         ^^^^^^^^^^^^^^^^^
@@ -875,7 +875,7 @@ LL | fn little_encourage_host() { fn_body_smol!(); }
    = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `u8::from_be_bytes`
-  --> tests/ui/endian_bytes.rs:77:9
+  --> tests/ui/endian_bytes.rs:79:9
    |
 LL |         u8::from_be_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -887,7 +887,7 @@ LL | fn little_encourage_host() { fn_body_smol!(); }
    = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `u8::to_ne_bytes` method
-  --> tests/ui/endian_bytes.rs:70:9
+  --> tests/ui/endian_bytes.rs:72:9
    |
 LL |         2u8.to_ne_bytes();
    |         ^^^^^^^^^^^^^^^^^
@@ -899,7 +899,7 @@ LL | fn little_encourage_big() { fn_body_smol!(); }
    = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `u8::from_ne_bytes`
-  --> tests/ui/endian_bytes.rs:71:9
+  --> tests/ui/endian_bytes.rs:73:9
    |
 LL |         u8::from_ne_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -911,7 +911,7 @@ LL | fn little_encourage_big() { fn_body_smol!(); }
    = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `u8::to_le_bytes` method
-  --> tests/ui/endian_bytes.rs:73:9
+  --> tests/ui/endian_bytes.rs:75:9
    |
 LL |         2u8.to_le_bytes();
    |         ^^^^^^^^^^^^^^^^^
@@ -923,7 +923,7 @@ LL | fn little_encourage_big() { fn_body_smol!(); }
    = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `u8::from_le_bytes`
-  --> tests/ui/endian_bytes.rs:74:9
+  --> tests/ui/endian_bytes.rs:76:9
    |
 LL |         u8::from_le_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -935,7 +935,7 @@ LL | fn little_encourage_big() { fn_body_smol!(); }
    = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `u8::to_le_bytes` method
-  --> tests/ui/endian_bytes.rs:73:9
+  --> tests/ui/endian_bytes.rs:75:9
    |
 LL |         2u8.to_le_bytes();
    |         ^^^^^^^^^^^^^^^^^
@@ -947,7 +947,7 @@ LL | fn big_encourage_host() { fn_body_smol!(); }
    = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `u8::from_le_bytes`
-  --> tests/ui/endian_bytes.rs:74:9
+  --> tests/ui/endian_bytes.rs:76:9
    |
 LL |         u8::from_le_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -959,7 +959,7 @@ LL | fn big_encourage_host() { fn_body_smol!(); }
    = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `u8::to_be_bytes` method
-  --> tests/ui/endian_bytes.rs:76:9
+  --> tests/ui/endian_bytes.rs:78:9
    |
 LL |         2u8.to_be_bytes();
    |         ^^^^^^^^^^^^^^^^^
@@ -971,7 +971,7 @@ LL | fn big_encourage_host() { fn_body_smol!(); }
    = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `u8::from_be_bytes`
-  --> tests/ui/endian_bytes.rs:77:9
+  --> tests/ui/endian_bytes.rs:79:9
    |
 LL |         u8::from_be_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -983,7 +983,7 @@ LL | fn big_encourage_host() { fn_body_smol!(); }
    = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `u8::to_ne_bytes` method
-  --> tests/ui/endian_bytes.rs:70:9
+  --> tests/ui/endian_bytes.rs:72:9
    |
 LL |         2u8.to_ne_bytes();
    |         ^^^^^^^^^^^^^^^^^
@@ -995,7 +995,7 @@ LL | fn big_encourage_little() { fn_body_smol!(); }
    = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `u8::from_ne_bytes`
-  --> tests/ui/endian_bytes.rs:71:9
+  --> tests/ui/endian_bytes.rs:73:9
    |
 LL |         u8::from_ne_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1007,7 +1007,7 @@ LL | fn big_encourage_little() { fn_body_smol!(); }
    = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `u8::to_be_bytes` method
-  --> tests/ui/endian_bytes.rs:76:9
+  --> tests/ui/endian_bytes.rs:78:9
    |
 LL |         2u8.to_be_bytes();
    |         ^^^^^^^^^^^^^^^^^
@@ -1019,7 +1019,7 @@ LL | fn big_encourage_little() { fn_body_smol!(); }
    = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the function `u8::from_be_bytes`
-  --> tests/ui/endian_bytes.rs:77:9
+  --> tests/ui/endian_bytes.rs:79:9
    |
 LL |         u8::from_be_bytes(todo!());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs
index 72097bfabd7..2634c56794e 100644
--- a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs
+++ b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs
@@ -1,4 +1,3 @@
-#![feature(lint_reasons)]
 //! This file tests the `#[expect]` attribute implementation for tool lints. The same
 //! file is used to test clippy and rustdoc. Any changes to this file should be synced
 //! to the other test files as well.
diff --git a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr
index 43e0b9279e4..f70d3408aa4 100644
--- a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr
+++ b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr
@@ -1,5 +1,5 @@
 error: this lint expectation is unfulfilled
-  --> tests/ui/expect_tool_lint_rfc_2383.rs:31:14
+  --> tests/ui/expect_tool_lint_rfc_2383.rs:30:14
    |
 LL |     #[expect(dead_code)]
    |              ^^^^^^^^^
@@ -8,31 +8,31 @@ LL |     #[expect(dead_code)]
    = help: to override `-D warnings` add `#[allow(unfulfilled_lint_expectations)]`
 
 error: this lint expectation is unfulfilled
-  --> tests/ui/expect_tool_lint_rfc_2383.rs:37:18
+  --> tests/ui/expect_tool_lint_rfc_2383.rs:36:18
    |
 LL |         #[expect(invalid_nan_comparisons)]
    |                  ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this lint expectation is unfulfilled
-  --> tests/ui/expect_tool_lint_rfc_2383.rs:108:14
+  --> tests/ui/expect_tool_lint_rfc_2383.rs:107:14
    |
 LL |     #[expect(clippy::almost_swapped)]
    |              ^^^^^^^^^^^^^^^^^^^^^^
 
 error: this lint expectation is unfulfilled
-  --> tests/ui/expect_tool_lint_rfc_2383.rs:116:14
+  --> tests/ui/expect_tool_lint_rfc_2383.rs:115:14
    |
 LL |     #[expect(clippy::bytes_nth)]
    |              ^^^^^^^^^^^^^^^^^
 
 error: this lint expectation is unfulfilled
-  --> tests/ui/expect_tool_lint_rfc_2383.rs:122:14
+  --> tests/ui/expect_tool_lint_rfc_2383.rs:121:14
    |
 LL |     #[expect(clippy::if_same_then_else)]
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this lint expectation is unfulfilled
-  --> tests/ui/expect_tool_lint_rfc_2383.rs:128:14
+  --> tests/ui/expect_tool_lint_rfc_2383.rs:127:14
    |
 LL |     #[expect(clippy::overly_complex_bool_expr)]
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/field_scoped_visibility_modifiers.rs b/src/tools/clippy/tests/ui/field_scoped_visibility_modifiers.rs
new file mode 100644
index 00000000000..5789dbf9b1d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/field_scoped_visibility_modifiers.rs
@@ -0,0 +1,21 @@
+#![warn(clippy::field_scoped_visibility_modifiers)]
+
+pub mod pub_module {
+    pub(in crate::pub_module) mod pub_in_path_module {}
+    pub(super) mod pub_super_module {}
+    struct MyStruct {
+        private_field: bool,
+        pub pub_field: bool,
+        pub(crate) pub_crate_field: bool,
+        pub(in crate::pub_module) pub_in_path_field: bool,
+        pub(super) pub_super_field: bool,
+        #[allow(clippy::needless_pub_self)]
+        pub(self) pub_self_field: bool,
+    }
+}
+pub(crate) mod pub_crate_module {}
+
+#[allow(clippy::needless_pub_self)]
+pub(self) mod pub_self_module {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/field_scoped_visibility_modifiers.stderr b/src/tools/clippy/tests/ui/field_scoped_visibility_modifiers.stderr
new file mode 100644
index 00000000000..beea6c92107
--- /dev/null
+++ b/src/tools/clippy/tests/ui/field_scoped_visibility_modifiers.stderr
@@ -0,0 +1,28 @@
+error: scoped visibility modifier on a field
+  --> tests/ui/field_scoped_visibility_modifiers.rs:9:9
+   |
+LL |         pub(crate) pub_crate_field: bool,
+   |         ^^^^^^^^^^
+   |
+   = help: consider making the field private and adding a scoped visibility method for it
+   = note: `-D clippy::field-scoped-visibility-modifiers` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::field_scoped_visibility_modifiers)]`
+
+error: scoped visibility modifier on a field
+  --> tests/ui/field_scoped_visibility_modifiers.rs:10:9
+   |
+LL |         pub(in crate::pub_module) pub_in_path_field: bool,
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider making the field private and adding a scoped visibility method for it
+
+error: scoped visibility modifier on a field
+  --> tests/ui/field_scoped_visibility_modifiers.rs:11:9
+   |
+LL |         pub(super) pub_super_field: bool,
+   |         ^^^^^^^^^^
+   |
+   = help: consider making the field private and adding a scoped visibility method for it
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/float_cmp.rs b/src/tools/clippy/tests/ui/float_cmp.rs
index 5057c643732..1923ad7c677 100644
--- a/src/tools/clippy/tests/ui/float_cmp.rs
+++ b/src/tools/clippy/tests/ui/float_cmp.rs
@@ -1,3 +1,5 @@
+// FIXME(f16_f128): const casting is not yet supported for these types. Add when available.
+
 #![warn(clippy::float_cmp)]
 #![allow(
     unused,
diff --git a/src/tools/clippy/tests/ui/float_cmp.stderr b/src/tools/clippy/tests/ui/float_cmp.stderr
index 49b65184f73..c8a0bde6e63 100644
--- a/src/tools/clippy/tests/ui/float_cmp.stderr
+++ b/src/tools/clippy/tests/ui/float_cmp.stderr
@@ -1,5 +1,5 @@
 error: strict comparison of `f32` or `f64`
-  --> tests/ui/float_cmp.rs:70:5
+  --> tests/ui/float_cmp.rs:72:5
    |
 LL |     ONE as f64 != 2.0;
    |     ^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(ONE as f64 - 2.0).abs() > error_margin`
@@ -9,7 +9,7 @@ LL |     ONE as f64 != 2.0;
    = help: to override `-D warnings` add `#[allow(clippy::float_cmp)]`
 
 error: strict comparison of `f32` or `f64`
-  --> tests/ui/float_cmp.rs:77:5
+  --> tests/ui/float_cmp.rs:79:5
    |
 LL |     x == 1.0;
    |     ^^^^^^^^ help: consider comparing them within some margin of error: `(x - 1.0).abs() < error_margin`
@@ -17,7 +17,7 @@ LL |     x == 1.0;
    = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64`
-  --> tests/ui/float_cmp.rs:82:5
+  --> tests/ui/float_cmp.rs:84:5
    |
 LL |     twice(x) != twice(ONE as f64);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(twice(x) - twice(ONE as f64)).abs() > error_margin`
@@ -25,7 +25,7 @@ LL |     twice(x) != twice(ONE as f64);
    = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64`
-  --> tests/ui/float_cmp.rs:104:5
+  --> tests/ui/float_cmp.rs:106:5
    |
 LL |     NON_ZERO_ARRAY[i] == NON_ZERO_ARRAY[j];
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(NON_ZERO_ARRAY[i] - NON_ZERO_ARRAY[j]).abs() < error_margin`
@@ -33,7 +33,7 @@ LL |     NON_ZERO_ARRAY[i] == NON_ZERO_ARRAY[j];
    = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64` arrays
-  --> tests/ui/float_cmp.rs:111:5
+  --> tests/ui/float_cmp.rs:113:5
    |
 LL |     a1 == a2;
    |     ^^^^^^^^
@@ -41,7 +41,7 @@ LL |     a1 == a2;
    = note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
 
 error: strict comparison of `f32` or `f64`
-  --> tests/ui/float_cmp.rs:114:5
+  --> tests/ui/float_cmp.rs:116:5
    |
 LL |     a1[0] == a2[0];
    |     ^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(a1[0] - a2[0]).abs() < error_margin`
diff --git a/src/tools/clippy/tests/ui/float_equality_without_abs.rs b/src/tools/clippy/tests/ui/float_equality_without_abs.rs
index 6363472d899..2b67c8bec10 100644
--- a/src/tools/clippy/tests/ui/float_equality_without_abs.rs
+++ b/src/tools/clippy/tests/ui/float_equality_without_abs.rs
@@ -1,5 +1,8 @@
 #![warn(clippy::float_equality_without_abs)]
 //@no-rustfix
+
+// FIXME(f16_f128): add tests for these types when abs is available
+
 pub fn is_roughly_equal(a: f32, b: f32) -> bool {
     (a - b) < f32::EPSILON
     //~^ ERROR: float equality check without `.abs()`
diff --git a/src/tools/clippy/tests/ui/float_equality_without_abs.stderr b/src/tools/clippy/tests/ui/float_equality_without_abs.stderr
index 0124dd983a3..cdaaf0cdbcf 100644
--- a/src/tools/clippy/tests/ui/float_equality_without_abs.stderr
+++ b/src/tools/clippy/tests/ui/float_equality_without_abs.stderr
@@ -1,5 +1,5 @@
 error: float equality check without `.abs()`
-  --> tests/ui/float_equality_without_abs.rs:4:5
+  --> tests/ui/float_equality_without_abs.rs:7:5
    |
 LL |     (a - b) < f32::EPSILON
    |     -------^^^^^^^^^^^^^^^
@@ -10,7 +10,7 @@ LL |     (a - b) < f32::EPSILON
    = help: to override `-D warnings` add `#[allow(clippy::float_equality_without_abs)]`
 
 error: float equality check without `.abs()`
-  --> tests/ui/float_equality_without_abs.rs:15:13
+  --> tests/ui/float_equality_without_abs.rs:18:13
    |
 LL |     let _ = (a - b) < f32::EPSILON;
    |             -------^^^^^^^^^^^^^^^
@@ -18,7 +18,7 @@ LL |     let _ = (a - b) < f32::EPSILON;
    |             help: add `.abs()`: `(a - b).abs()`
 
 error: float equality check without `.abs()`
-  --> tests/ui/float_equality_without_abs.rs:17:13
+  --> tests/ui/float_equality_without_abs.rs:20:13
    |
 LL |     let _ = a - b < f32::EPSILON;
    |             -----^^^^^^^^^^^^^^^
@@ -26,7 +26,7 @@ LL |     let _ = a - b < f32::EPSILON;
    |             help: add `.abs()`: `(a - b).abs()`
 
 error: float equality check without `.abs()`
-  --> tests/ui/float_equality_without_abs.rs:19:13
+  --> tests/ui/float_equality_without_abs.rs:22:13
    |
 LL |     let _ = a - b.abs() < f32::EPSILON;
    |             -----------^^^^^^^^^^^^^^^
@@ -34,7 +34,7 @@ LL |     let _ = a - b.abs() < f32::EPSILON;
    |             help: add `.abs()`: `(a - b.abs()).abs()`
 
 error: float equality check without `.abs()`
-  --> tests/ui/float_equality_without_abs.rs:21:13
+  --> tests/ui/float_equality_without_abs.rs:24:13
    |
 LL |     let _ = (a as f64 - b as f64) < f64::EPSILON;
    |             ---------------------^^^^^^^^^^^^^^^
@@ -42,7 +42,7 @@ LL |     let _ = (a as f64 - b as f64) < f64::EPSILON;
    |             help: add `.abs()`: `(a as f64 - b as f64).abs()`
 
 error: float equality check without `.abs()`
-  --> tests/ui/float_equality_without_abs.rs:23:13
+  --> tests/ui/float_equality_without_abs.rs:26:13
    |
 LL |     let _ = 1.0 - 2.0 < f32::EPSILON;
    |             ---------^^^^^^^^^^^^^^^
@@ -50,7 +50,7 @@ LL |     let _ = 1.0 - 2.0 < f32::EPSILON;
    |             help: add `.abs()`: `(1.0 - 2.0).abs()`
 
 error: float equality check without `.abs()`
-  --> tests/ui/float_equality_without_abs.rs:26:13
+  --> tests/ui/float_equality_without_abs.rs:29:13
    |
 LL |     let _ = f32::EPSILON > (a - b);
    |             ^^^^^^^^^^^^^^^-------
@@ -58,7 +58,7 @@ LL |     let _ = f32::EPSILON > (a - b);
    |                            help: add `.abs()`: `(a - b).abs()`
 
 error: float equality check without `.abs()`
-  --> tests/ui/float_equality_without_abs.rs:28:13
+  --> tests/ui/float_equality_without_abs.rs:31:13
    |
 LL |     let _ = f32::EPSILON > a - b;
    |             ^^^^^^^^^^^^^^^-----
@@ -66,7 +66,7 @@ LL |     let _ = f32::EPSILON > a - b;
    |                            help: add `.abs()`: `(a - b).abs()`
 
 error: float equality check without `.abs()`
-  --> tests/ui/float_equality_without_abs.rs:30:13
+  --> tests/ui/float_equality_without_abs.rs:33:13
    |
 LL |     let _ = f32::EPSILON > a - b.abs();
    |             ^^^^^^^^^^^^^^^-----------
@@ -74,7 +74,7 @@ LL |     let _ = f32::EPSILON > a - b.abs();
    |                            help: add `.abs()`: `(a - b.abs()).abs()`
 
 error: float equality check without `.abs()`
-  --> tests/ui/float_equality_without_abs.rs:32:13
+  --> tests/ui/float_equality_without_abs.rs:35:13
    |
 LL |     let _ = f64::EPSILON > (a as f64 - b as f64);
    |             ^^^^^^^^^^^^^^^---------------------
@@ -82,7 +82,7 @@ LL |     let _ = f64::EPSILON > (a as f64 - b as f64);
    |                            help: add `.abs()`: `(a as f64 - b as f64).abs()`
 
 error: float equality check without `.abs()`
-  --> tests/ui/float_equality_without_abs.rs:34:13
+  --> tests/ui/float_equality_without_abs.rs:37:13
    |
 LL |     let _ = f32::EPSILON > 1.0 - 2.0;
    |             ^^^^^^^^^^^^^^^---------
diff --git a/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs b/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs
index a42c6383cce..47c113d61c0 100644
--- a/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs
+++ b/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs
@@ -3,8 +3,8 @@
 #![warn(clippy::suboptimal_flops)]
 #![no_std]
 
-// The following should not lint, as the suggested methods {f32,f64}.mul_add()
-// and {f32,f64}::abs() are not available in no_std
+// The following should not lint, as the suggested methods `{f16,f32,f64,f128}.mul_add()`
+// and ``{f16,f32,f64,f128}::abs()` are not available in no_std
 
 pub fn mul_add() {
     let a: f64 = 1234.567;
diff --git a/src/tools/clippy/tests/ui/floating_point_exp.fixed b/src/tools/clippy/tests/ui/floating_point_exp.fixed
index 15072bb1ee9..fbd91cbc9d7 100644
--- a/src/tools/clippy/tests/ui/floating_point_exp.fixed
+++ b/src/tools/clippy/tests/ui/floating_point_exp.fixed
@@ -1,3 +1,5 @@
+// FIXME(f16_f128): add tests when exp is available
+
 #![warn(clippy::imprecise_flops)]
 #![allow(clippy::unnecessary_cast)]
 
diff --git a/src/tools/clippy/tests/ui/floating_point_exp.rs b/src/tools/clippy/tests/ui/floating_point_exp.rs
index 7d8b17946d0..340bacaf56b 100644
--- a/src/tools/clippy/tests/ui/floating_point_exp.rs
+++ b/src/tools/clippy/tests/ui/floating_point_exp.rs
@@ -1,3 +1,5 @@
+// FIXME(f16_f128): add tests when exp is available
+
 #![warn(clippy::imprecise_flops)]
 #![allow(clippy::unnecessary_cast)]
 
diff --git a/src/tools/clippy/tests/ui/floating_point_exp.stderr b/src/tools/clippy/tests/ui/floating_point_exp.stderr
index a19edf87e24..6ce67254abc 100644
--- a/src/tools/clippy/tests/ui/floating_point_exp.stderr
+++ b/src/tools/clippy/tests/ui/floating_point_exp.stderr
@@ -1,5 +1,5 @@
 error: (e.pow(x) - 1) can be computed more accurately
-  --> tests/ui/floating_point_exp.rs:6:13
+  --> tests/ui/floating_point_exp.rs:8:13
    |
 LL |     let _ = x.exp() - 1.0;
    |             ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()`
@@ -8,25 +8,25 @@ LL |     let _ = x.exp() - 1.0;
    = help: to override `-D warnings` add `#[allow(clippy::imprecise_flops)]`
 
 error: (e.pow(x) - 1) can be computed more accurately
-  --> tests/ui/floating_point_exp.rs:7:13
+  --> tests/ui/floating_point_exp.rs:9:13
    |
 LL |     let _ = x.exp() - 1.0 + 2.0;
    |             ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()`
 
 error: (e.pow(x) - 1) can be computed more accurately
-  --> tests/ui/floating_point_exp.rs:8:13
+  --> tests/ui/floating_point_exp.rs:10:13
    |
 LL |     let _ = (x as f32).exp() - 1.0 + 2.0;
    |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).exp_m1()`
 
 error: (e.pow(x) - 1) can be computed more accurately
-  --> tests/ui/floating_point_exp.rs:14:13
+  --> tests/ui/floating_point_exp.rs:16:13
    |
 LL |     let _ = x.exp() - 1.0;
    |             ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()`
 
 error: (e.pow(x) - 1) can be computed more accurately
-  --> tests/ui/floating_point_exp.rs:15:13
+  --> tests/ui/floating_point_exp.rs:17:13
    |
 LL |     let _ = x.exp() - 1.0 + 2.0;
    |             ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()`
diff --git a/src/tools/clippy/tests/ui/floating_point_log.fixed b/src/tools/clippy/tests/ui/floating_point_log.fixed
index 15cc47eef0d..75e9c40a521 100644
--- a/src/tools/clippy/tests/ui/floating_point_log.fixed
+++ b/src/tools/clippy/tests/ui/floating_point_log.fixed
@@ -1,6 +1,8 @@
 #![allow(dead_code, clippy::double_parens, clippy::unnecessary_cast)]
 #![warn(clippy::suboptimal_flops, clippy::imprecise_flops)]
 
+// FIXME(f16_f128): add tests for these types once math functions are available
+
 const TWO: f32 = 2.0;
 const E: f32 = std::f32::consts::E;
 
diff --git a/src/tools/clippy/tests/ui/floating_point_log.rs b/src/tools/clippy/tests/ui/floating_point_log.rs
index 1241af82859..d68369a3861 100644
--- a/src/tools/clippy/tests/ui/floating_point_log.rs
+++ b/src/tools/clippy/tests/ui/floating_point_log.rs
@@ -1,6 +1,8 @@
 #![allow(dead_code, clippy::double_parens, clippy::unnecessary_cast)]
 #![warn(clippy::suboptimal_flops, clippy::imprecise_flops)]
 
+// FIXME(f16_f128): add tests for these types once math functions are available
+
 const TWO: f32 = 2.0;
 const E: f32 = std::f32::consts::E;
 
diff --git a/src/tools/clippy/tests/ui/floating_point_log.stderr b/src/tools/clippy/tests/ui/floating_point_log.stderr
index 3a449a98ead..19c28de8e39 100644
--- a/src/tools/clippy/tests/ui/floating_point_log.stderr
+++ b/src/tools/clippy/tests/ui/floating_point_log.stderr
@@ -1,5 +1,5 @@
 error: logarithm for bases 2, 10 and e can be computed more accurately
-  --> tests/ui/floating_point_log.rs:9:13
+  --> tests/ui/floating_point_log.rs:11:13
    |
 LL |     let _ = x.log(2f32);
    |             ^^^^^^^^^^^ help: consider using: `x.log2()`
@@ -8,55 +8,55 @@ LL |     let _ = x.log(2f32);
    = help: to override `-D warnings` add `#[allow(clippy::suboptimal_flops)]`
 
 error: logarithm for bases 2, 10 and e can be computed more accurately
-  --> tests/ui/floating_point_log.rs:10:13
+  --> tests/ui/floating_point_log.rs:12:13
    |
 LL |     let _ = x.log(10f32);
    |             ^^^^^^^^^^^^ help: consider using: `x.log10()`
 
 error: logarithm for bases 2, 10 and e can be computed more accurately
-  --> tests/ui/floating_point_log.rs:11:13
+  --> tests/ui/floating_point_log.rs:13:13
    |
 LL |     let _ = x.log(std::f32::consts::E);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.ln()`
 
 error: logarithm for bases 2, 10 and e can be computed more accurately
-  --> tests/ui/floating_point_log.rs:12:13
+  --> tests/ui/floating_point_log.rs:14:13
    |
 LL |     let _ = x.log(TWO);
    |             ^^^^^^^^^^ help: consider using: `x.log2()`
 
 error: logarithm for bases 2, 10 and e can be computed more accurately
-  --> tests/ui/floating_point_log.rs:13:13
+  --> tests/ui/floating_point_log.rs:15:13
    |
 LL |     let _ = x.log(E);
    |             ^^^^^^^^ help: consider using: `x.ln()`
 
 error: logarithm for bases 2, 10 and e can be computed more accurately
-  --> tests/ui/floating_point_log.rs:14:13
+  --> tests/ui/floating_point_log.rs:16:13
    |
 LL |     let _ = (x as f32).log(2f32);
    |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).log2()`
 
 error: logarithm for bases 2, 10 and e can be computed more accurately
-  --> tests/ui/floating_point_log.rs:17:13
+  --> tests/ui/floating_point_log.rs:19:13
    |
 LL |     let _ = x.log(2f64);
    |             ^^^^^^^^^^^ help: consider using: `x.log2()`
 
 error: logarithm for bases 2, 10 and e can be computed more accurately
-  --> tests/ui/floating_point_log.rs:18:13
+  --> tests/ui/floating_point_log.rs:20:13
    |
 LL |     let _ = x.log(10f64);
    |             ^^^^^^^^^^^^ help: consider using: `x.log10()`
 
 error: logarithm for bases 2, 10 and e can be computed more accurately
-  --> tests/ui/floating_point_log.rs:19:13
+  --> tests/ui/floating_point_log.rs:21:13
    |
 LL |     let _ = x.log(std::f64::consts::E);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.ln()`
 
 error: ln(1 + x) can be computed more accurately
-  --> tests/ui/floating_point_log.rs:24:13
+  --> tests/ui/floating_point_log.rs:26:13
    |
 LL |     let _ = (1f32 + 2.).ln();
    |             ^^^^^^^^^^^^^^^^ help: consider using: `2.0f32.ln_1p()`
@@ -65,115 +65,115 @@ LL |     let _ = (1f32 + 2.).ln();
    = help: to override `-D warnings` add `#[allow(clippy::imprecise_flops)]`
 
 error: ln(1 + x) can be computed more accurately
-  --> tests/ui/floating_point_log.rs:25:13
+  --> tests/ui/floating_point_log.rs:27:13
    |
 LL |     let _ = (1f32 + 2.0).ln();
    |             ^^^^^^^^^^^^^^^^^ help: consider using: `2.0f32.ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> tests/ui/floating_point_log.rs:26:13
+  --> tests/ui/floating_point_log.rs:28:13
    |
 LL |     let _ = (1.0 + x).ln();
    |             ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> tests/ui/floating_point_log.rs:27:13
+  --> tests/ui/floating_point_log.rs:29:13
    |
 LL |     let _ = (1.0 + x / 2.0).ln();
    |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> tests/ui/floating_point_log.rs:28:13
+  --> tests/ui/floating_point_log.rs:30:13
    |
 LL |     let _ = (1.0 + x.powi(3)).ln();
    |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> tests/ui/floating_point_log.rs:29:13
+  --> tests/ui/floating_point_log.rs:31:13
    |
 LL |     let _ = (1.0 + x.powi(3) / 2.0).ln();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x.powi(3) / 2.0).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> tests/ui/floating_point_log.rs:30:13
+  --> tests/ui/floating_point_log.rs:32:13
    |
 LL |     let _ = (1.0 + (std::f32::consts::E - 1.0)).ln();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(std::f32::consts::E - 1.0).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> tests/ui/floating_point_log.rs:31:13
+  --> tests/ui/floating_point_log.rs:33:13
    |
 LL |     let _ = (x + 1.0).ln();
    |             ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> tests/ui/floating_point_log.rs:32:13
+  --> tests/ui/floating_point_log.rs:34:13
    |
 LL |     let _ = (x.powi(3) + 1.0).ln();
    |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> tests/ui/floating_point_log.rs:33:13
+  --> tests/ui/floating_point_log.rs:35:13
    |
 LL |     let _ = (x + 2.0 + 1.0).ln();
    |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x + 2.0).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> tests/ui/floating_point_log.rs:34:13
+  --> tests/ui/floating_point_log.rs:36:13
    |
 LL |     let _ = (x / 2.0 + 1.0).ln();
    |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> tests/ui/floating_point_log.rs:42:13
+  --> tests/ui/floating_point_log.rs:44:13
    |
 LL |     let _ = (1f64 + 2.).ln();
    |             ^^^^^^^^^^^^^^^^ help: consider using: `2.0f64.ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> tests/ui/floating_point_log.rs:43:13
+  --> tests/ui/floating_point_log.rs:45:13
    |
 LL |     let _ = (1f64 + 2.0).ln();
    |             ^^^^^^^^^^^^^^^^^ help: consider using: `2.0f64.ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> tests/ui/floating_point_log.rs:44:13
+  --> tests/ui/floating_point_log.rs:46:13
    |
 LL |     let _ = (1.0 + x).ln();
    |             ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> tests/ui/floating_point_log.rs:45:13
+  --> tests/ui/floating_point_log.rs:47:13
    |
 LL |     let _ = (1.0 + x / 2.0).ln();
    |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> tests/ui/floating_point_log.rs:46:13
+  --> tests/ui/floating_point_log.rs:48:13
    |
 LL |     let _ = (1.0 + x.powi(3)).ln();
    |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> tests/ui/floating_point_log.rs:47:13
+  --> tests/ui/floating_point_log.rs:49:13
    |
 LL |     let _ = (x + 1.0).ln();
    |             ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> tests/ui/floating_point_log.rs:48:13
+  --> tests/ui/floating_point_log.rs:50:13
    |
 LL |     let _ = (x.powi(3) + 1.0).ln();
    |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> tests/ui/floating_point_log.rs:49:13
+  --> tests/ui/floating_point_log.rs:51:13
    |
 LL |     let _ = (x + 2.0 + 1.0).ln();
    |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x + 2.0).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> tests/ui/floating_point_log.rs:50:13
+  --> tests/ui/floating_point_log.rs:52:13
    |
 LL |     let _ = (x / 2.0 + 1.0).ln();
    |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()`
diff --git a/src/tools/clippy/tests/ui/floating_point_powf.fixed b/src/tools/clippy/tests/ui/floating_point_powf.fixed
index c2884ca318c..a44938fdf69 100644
--- a/src/tools/clippy/tests/ui/floating_point_powf.fixed
+++ b/src/tools/clippy/tests/ui/floating_point_powf.fixed
@@ -1,6 +1,8 @@
 #![warn(clippy::suboptimal_flops, clippy::imprecise_flops)]
 #![allow(clippy::unnecessary_cast)]
 
+// FIXME(f16_f128): add tests for these types when `powf` is available
+
 fn main() {
     let x = 3f32;
     let _ = x.exp2();
diff --git a/src/tools/clippy/tests/ui/floating_point_powf.rs b/src/tools/clippy/tests/ui/floating_point_powf.rs
index 37d58af0551..80f6c1791d7 100644
--- a/src/tools/clippy/tests/ui/floating_point_powf.rs
+++ b/src/tools/clippy/tests/ui/floating_point_powf.rs
@@ -1,6 +1,8 @@
 #![warn(clippy::suboptimal_flops, clippy::imprecise_flops)]
 #![allow(clippy::unnecessary_cast)]
 
+// FIXME(f16_f128): add tests for these types when `powf` is available
+
 fn main() {
     let x = 3f32;
     let _ = 2f32.powf(x);
diff --git a/src/tools/clippy/tests/ui/floating_point_powf.stderr b/src/tools/clippy/tests/ui/floating_point_powf.stderr
index bd3fa771fe5..671383401b5 100644
--- a/src/tools/clippy/tests/ui/floating_point_powf.stderr
+++ b/src/tools/clippy/tests/ui/floating_point_powf.stderr
@@ -1,5 +1,5 @@
 error: exponent for bases 2 and e can be computed more accurately
-  --> tests/ui/floating_point_powf.rs:6:13
+  --> tests/ui/floating_point_powf.rs:8:13
    |
 LL |     let _ = 2f32.powf(x);
    |             ^^^^^^^^^^^^ help: consider using: `x.exp2()`
@@ -8,43 +8,43 @@ LL |     let _ = 2f32.powf(x);
    = help: to override `-D warnings` add `#[allow(clippy::suboptimal_flops)]`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> tests/ui/floating_point_powf.rs:7:13
+  --> tests/ui/floating_point_powf.rs:9:13
    |
 LL |     let _ = 2f32.powf(3.1);
    |             ^^^^^^^^^^^^^^ help: consider using: `3.1f32.exp2()`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> tests/ui/floating_point_powf.rs:8:13
+  --> tests/ui/floating_point_powf.rs:10:13
    |
 LL |     let _ = 2f32.powf(-3.1);
    |             ^^^^^^^^^^^^^^^ help: consider using: `(-3.1f32).exp2()`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> tests/ui/floating_point_powf.rs:9:13
+  --> tests/ui/floating_point_powf.rs:11:13
    |
 LL |     let _ = std::f32::consts::E.powf(x);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> tests/ui/floating_point_powf.rs:10:13
+  --> tests/ui/floating_point_powf.rs:12:13
    |
 LL |     let _ = std::f32::consts::E.powf(3.1);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `3.1f32.exp()`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> tests/ui/floating_point_powf.rs:11:13
+  --> tests/ui/floating_point_powf.rs:13:13
    |
 LL |     let _ = std::f32::consts::E.powf(-3.1);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-3.1f32).exp()`
 
 error: square-root of a number can be computed more efficiently and accurately
-  --> tests/ui/floating_point_powf.rs:12:13
+  --> tests/ui/floating_point_powf.rs:14:13
    |
 LL |     let _ = x.powf(1.0 / 2.0);
    |             ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()`
 
 error: cube-root of a number can be computed more accurately
-  --> tests/ui/floating_point_powf.rs:13:13
+  --> tests/ui/floating_point_powf.rs:15:13
    |
 LL |     let _ = x.powf(1.0 / 3.0);
    |             ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()`
@@ -53,139 +53,139 @@ LL |     let _ = x.powf(1.0 / 3.0);
    = help: to override `-D warnings` add `#[allow(clippy::imprecise_flops)]`
 
 error: cube-root of a number can be computed more accurately
-  --> tests/ui/floating_point_powf.rs:14:13
+  --> tests/ui/floating_point_powf.rs:16:13
    |
 LL |     let _ = (x as f32).powf(1.0 / 3.0);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).cbrt()`
 
 error: exponentiation with integer powers can be computed more efficiently
-  --> tests/ui/floating_point_powf.rs:15:13
+  --> tests/ui/floating_point_powf.rs:17:13
    |
 LL |     let _ = x.powf(3.0);
    |             ^^^^^^^^^^^ help: consider using: `x.powi(3)`
 
 error: exponentiation with integer powers can be computed more efficiently
-  --> tests/ui/floating_point_powf.rs:16:13
+  --> tests/ui/floating_point_powf.rs:18:13
    |
 LL |     let _ = x.powf(-2.0);
    |             ^^^^^^^^^^^^ help: consider using: `x.powi(-2)`
 
 error: exponentiation with integer powers can be computed more efficiently
-  --> tests/ui/floating_point_powf.rs:17:13
+  --> tests/ui/floating_point_powf.rs:19:13
    |
 LL |     let _ = x.powf(16_777_215.0);
    |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(16_777_215)`
 
 error: exponentiation with integer powers can be computed more efficiently
-  --> tests/ui/floating_point_powf.rs:18:13
+  --> tests/ui/floating_point_powf.rs:20:13
    |
 LL |     let _ = x.powf(-16_777_215.0);
    |             ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(-16_777_215)`
 
 error: exponentiation with integer powers can be computed more efficiently
-  --> tests/ui/floating_point_powf.rs:19:13
+  --> tests/ui/floating_point_powf.rs:21:13
    |
 LL |     let _ = (x as f32).powf(-16_777_215.0);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).powi(-16_777_215)`
 
 error: exponentiation with integer powers can be computed more efficiently
-  --> tests/ui/floating_point_powf.rs:20:13
+  --> tests/ui/floating_point_powf.rs:22:13
    |
 LL |     let _ = (x as f32).powf(3.0);
    |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).powi(3)`
 
 error: cube-root of a number can be computed more accurately
-  --> tests/ui/floating_point_powf.rs:21:13
+  --> tests/ui/floating_point_powf.rs:23:13
    |
 LL |     let _ = (1.5_f32 + 1.0).powf(1.0 / 3.0);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(1.5_f32 + 1.0).cbrt()`
 
 error: cube-root of a number can be computed more accurately
-  --> tests/ui/floating_point_powf.rs:22:13
+  --> tests/ui/floating_point_powf.rs:24:13
    |
 LL |     let _ = 1.5_f64.powf(1.0 / 3.0);
    |             ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1.5_f64.cbrt()`
 
 error: square-root of a number can be computed more efficiently and accurately
-  --> tests/ui/floating_point_powf.rs:23:13
+  --> tests/ui/floating_point_powf.rs:25:13
    |
 LL |     let _ = 1.5_f64.powf(1.0 / 2.0);
    |             ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1.5_f64.sqrt()`
 
 error: exponentiation with integer powers can be computed more efficiently
-  --> tests/ui/floating_point_powf.rs:24:13
+  --> tests/ui/floating_point_powf.rs:26:13
    |
 LL |     let _ = 1.5_f64.powf(3.0);
    |             ^^^^^^^^^^^^^^^^^ help: consider using: `1.5_f64.powi(3)`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> tests/ui/floating_point_powf.rs:33:13
+  --> tests/ui/floating_point_powf.rs:35:13
    |
 LL |     let _ = 2f64.powf(x);
    |             ^^^^^^^^^^^^ help: consider using: `x.exp2()`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> tests/ui/floating_point_powf.rs:34:13
+  --> tests/ui/floating_point_powf.rs:36:13
    |
 LL |     let _ = 2f64.powf(3.1);
    |             ^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp2()`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> tests/ui/floating_point_powf.rs:35:13
+  --> tests/ui/floating_point_powf.rs:37:13
    |
 LL |     let _ = 2f64.powf(-3.1);
    |             ^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp2()`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> tests/ui/floating_point_powf.rs:36:13
+  --> tests/ui/floating_point_powf.rs:38:13
    |
 LL |     let _ = std::f64::consts::E.powf(x);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> tests/ui/floating_point_powf.rs:37:13
+  --> tests/ui/floating_point_powf.rs:39:13
    |
 LL |     let _ = std::f64::consts::E.powf(3.1);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp()`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> tests/ui/floating_point_powf.rs:38:13
+  --> tests/ui/floating_point_powf.rs:40:13
    |
 LL |     let _ = std::f64::consts::E.powf(-3.1);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp()`
 
 error: square-root of a number can be computed more efficiently and accurately
-  --> tests/ui/floating_point_powf.rs:39:13
+  --> tests/ui/floating_point_powf.rs:41:13
    |
 LL |     let _ = x.powf(1.0 / 2.0);
    |             ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()`
 
 error: cube-root of a number can be computed more accurately
-  --> tests/ui/floating_point_powf.rs:40:13
+  --> tests/ui/floating_point_powf.rs:42:13
    |
 LL |     let _ = x.powf(1.0 / 3.0);
    |             ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()`
 
 error: exponentiation with integer powers can be computed more efficiently
-  --> tests/ui/floating_point_powf.rs:41:13
+  --> tests/ui/floating_point_powf.rs:43:13
    |
 LL |     let _ = x.powf(3.0);
    |             ^^^^^^^^^^^ help: consider using: `x.powi(3)`
 
 error: exponentiation with integer powers can be computed more efficiently
-  --> tests/ui/floating_point_powf.rs:42:13
+  --> tests/ui/floating_point_powf.rs:44:13
    |
 LL |     let _ = x.powf(-2.0);
    |             ^^^^^^^^^^^^ help: consider using: `x.powi(-2)`
 
 error: exponentiation with integer powers can be computed more efficiently
-  --> tests/ui/floating_point_powf.rs:43:13
+  --> tests/ui/floating_point_powf.rs:45:13
    |
 LL |     let _ = x.powf(-2_147_483_648.0);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(-2_147_483_648)`
 
 error: exponentiation with integer powers can be computed more efficiently
-  --> tests/ui/floating_point_powf.rs:44:13
+  --> tests/ui/floating_point_powf.rs:46:13
    |
 LL |     let _ = x.powf(2_147_483_647.0);
    |             ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2_147_483_647)`
diff --git a/src/tools/clippy/tests/ui/implicit_return.fixed b/src/tools/clippy/tests/ui/implicit_return.fixed
index 897f1b76616..56fe29b4e67 100644
--- a/src/tools/clippy/tests/ui/implicit_return.fixed
+++ b/src/tools/clippy/tests/ui/implicit_return.fixed
@@ -1,7 +1,11 @@
-#![feature(lint_reasons)]
+//@aux-build: proc_macros.rs
+
 #![warn(clippy::implicit_return)]
 #![allow(clippy::needless_return, clippy::needless_bool, unused, clippy::never_loop)]
 
+extern crate proc_macros;
+use proc_macros::with_span;
+
 fn test_end_of_fn() -> bool {
     if true {
         // no error!
@@ -137,3 +141,11 @@ fn check_expect() -> bool {
     #[expect(clippy::implicit_return)]
     true
 }
+
+with_span!(
+    span
+
+    fn dont_lint_proc_macro(x: usize) -> usize{
+        x
+    }
+);
diff --git a/src/tools/clippy/tests/ui/implicit_return.rs b/src/tools/clippy/tests/ui/implicit_return.rs
index fcff67b5807..f066ce20cfd 100644
--- a/src/tools/clippy/tests/ui/implicit_return.rs
+++ b/src/tools/clippy/tests/ui/implicit_return.rs
@@ -1,7 +1,11 @@
-#![feature(lint_reasons)]
+//@aux-build: proc_macros.rs
+
 #![warn(clippy::implicit_return)]
 #![allow(clippy::needless_return, clippy::needless_bool, unused, clippy::never_loop)]
 
+extern crate proc_macros;
+use proc_macros::with_span;
+
 fn test_end_of_fn() -> bool {
     if true {
         // no error!
@@ -137,3 +141,11 @@ fn check_expect() -> bool {
     #[expect(clippy::implicit_return)]
     true
 }
+
+with_span!(
+    span
+
+    fn dont_lint_proc_macro(x: usize) -> usize{
+        x
+    }
+);
diff --git a/src/tools/clippy/tests/ui/implicit_return.stderr b/src/tools/clippy/tests/ui/implicit_return.stderr
index 3ffed273e0f..f06d4e983c5 100644
--- a/src/tools/clippy/tests/ui/implicit_return.stderr
+++ b/src/tools/clippy/tests/ui/implicit_return.stderr
@@ -1,5 +1,5 @@
 error: missing `return` statement
-  --> tests/ui/implicit_return.rs:11:5
+  --> tests/ui/implicit_return.rs:15:5
    |
 LL |     true
    |     ^^^^ help: add `return` as shown: `return true`
@@ -8,85 +8,85 @@ LL |     true
    = help: to override `-D warnings` add `#[allow(clippy::implicit_return)]`
 
 error: missing `return` statement
-  --> tests/ui/implicit_return.rs:15:15
+  --> tests/ui/implicit_return.rs:19:15
    |
 LL |     if true { true } else { false }
    |               ^^^^ help: add `return` as shown: `return true`
 
 error: missing `return` statement
-  --> tests/ui/implicit_return.rs:15:29
+  --> tests/ui/implicit_return.rs:19:29
    |
 LL |     if true { true } else { false }
    |                             ^^^^^ help: add `return` as shown: `return false`
 
 error: missing `return` statement
-  --> tests/ui/implicit_return.rs:21:17
+  --> tests/ui/implicit_return.rs:25:17
    |
 LL |         true => false,
    |                 ^^^^^ help: add `return` as shown: `return false`
 
 error: missing `return` statement
-  --> tests/ui/implicit_return.rs:22:20
+  --> tests/ui/implicit_return.rs:26:20
    |
 LL |         false => { true },
    |                    ^^^^ help: add `return` as shown: `return true`
 
 error: missing `return` statement
-  --> tests/ui/implicit_return.rs:35:9
+  --> tests/ui/implicit_return.rs:39:9
    |
 LL |         break true;
    |         ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
 
 error: missing `return` statement
-  --> tests/ui/implicit_return.rs:42:13
+  --> tests/ui/implicit_return.rs:46:13
    |
 LL |             break true;
    |             ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
 
 error: missing `return` statement
-  --> tests/ui/implicit_return.rs:50:13
+  --> tests/ui/implicit_return.rs:54:13
    |
 LL |             break true;
    |             ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
 
 error: missing `return` statement
-  --> tests/ui/implicit_return.rs:68:18
+  --> tests/ui/implicit_return.rs:72:18
    |
 LL |     let _ = || { true };
    |                  ^^^^ help: add `return` as shown: `return true`
 
 error: missing `return` statement
-  --> tests/ui/implicit_return.rs:69:16
+  --> tests/ui/implicit_return.rs:73:16
    |
 LL |     let _ = || true;
    |                ^^^^ help: add `return` as shown: `return true`
 
 error: missing `return` statement
-  --> tests/ui/implicit_return.rs:77:5
+  --> tests/ui/implicit_return.rs:81:5
    |
 LL |     format!("test {}", "test")
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `return` as shown: `return format!("test {}", "test")`
 
 error: missing `return` statement
-  --> tests/ui/implicit_return.rs:86:5
+  --> tests/ui/implicit_return.rs:90:5
    |
 LL |     m!(true, false)
    |     ^^^^^^^^^^^^^^^ help: add `return` as shown: `return m!(true, false)`
 
 error: missing `return` statement
-  --> tests/ui/implicit_return.rs:92:13
+  --> tests/ui/implicit_return.rs:96:13
    |
 LL |             break true;
    |             ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
 
 error: missing `return` statement
-  --> tests/ui/implicit_return.rs:97:17
+  --> tests/ui/implicit_return.rs:101:17
    |
 LL |                 break 'outer false;
    |                 ^^^^^^^^^^^^^^^^^^ help: change `break` to `return` as shown: `return false`
 
 error: missing `return` statement
-  --> tests/ui/implicit_return.rs:112:5
+  --> tests/ui/implicit_return.rs:116:5
    |
 LL | /     loop {
 LL | |         m!(true);
@@ -101,7 +101,7 @@ LL +     }
    |
 
 error: missing `return` statement
-  --> tests/ui/implicit_return.rs:126:5
+  --> tests/ui/implicit_return.rs:130:5
    |
 LL |     true
    |     ^^^^ help: add `return` as shown: `return true`
diff --git a/src/tools/clippy/tests/ui/let_unit.fixed b/src/tools/clippy/tests/ui/let_unit.fixed
index 20940daffa7..3456e274f6a 100644
--- a/src/tools/clippy/tests/ui/let_unit.fixed
+++ b/src/tools/clippy/tests/ui/let_unit.fixed
@@ -1,4 +1,3 @@
-#![feature(lint_reasons)]
 #![warn(clippy::let_unit_value)]
 #![allow(unused, clippy::no_effect, clippy::needless_late_init, path_statements)]
 
diff --git a/src/tools/clippy/tests/ui/let_unit.rs b/src/tools/clippy/tests/ui/let_unit.rs
index dca66f2e3ed..e2dafbcb771 100644
--- a/src/tools/clippy/tests/ui/let_unit.rs
+++ b/src/tools/clippy/tests/ui/let_unit.rs
@@ -1,4 +1,3 @@
-#![feature(lint_reasons)]
 #![warn(clippy::let_unit_value)]
 #![allow(unused, clippy::no_effect, clippy::needless_late_init, path_statements)]
 
diff --git a/src/tools/clippy/tests/ui/let_unit.stderr b/src/tools/clippy/tests/ui/let_unit.stderr
index aafb77bcd0d..2f62c33c887 100644
--- a/src/tools/clippy/tests/ui/let_unit.stderr
+++ b/src/tools/clippy/tests/ui/let_unit.stderr
@@ -1,5 +1,5 @@
 error: this let-binding has unit value
-  --> tests/ui/let_unit.rs:12:5
+  --> tests/ui/let_unit.rs:11:5
    |
 LL |     let _x = println!("x");
    |     ^^^^^^^^^^^^^^^^^^^^^^^ help: omit the `let` binding: `println!("x");`
@@ -8,7 +8,7 @@ LL |     let _x = println!("x");
    = help: to override `-D warnings` add `#[allow(clippy::let_unit_value)]`
 
 error: this let-binding has unit value
-  --> tests/ui/let_unit.rs:60:5
+  --> tests/ui/let_unit.rs:59:5
    |
 LL | /     let _ = v
 LL | |         .into_iter()
@@ -31,7 +31,7 @@ LL +         .unwrap();
    |
 
 error: this let-binding has unit value
-  --> tests/ui/let_unit.rs:109:5
+  --> tests/ui/let_unit.rs:108:5
    |
 LL | /     let x = match Some(0) {
 LL | |         None => f2(1),
@@ -52,7 +52,7 @@ LL +     };
    |
 
 error: this let-binding has unit value
-  --> tests/ui/let_unit.rs:190:9
+  --> tests/ui/let_unit.rs:189:9
    |
 LL |         let res = returns_unit();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/lossy_float_literal.fixed b/src/tools/clippy/tests/ui/lossy_float_literal.fixed
index 92a0084a6ae..cc8c0b4a0d1 100644
--- a/src/tools/clippy/tests/ui/lossy_float_literal.fixed
+++ b/src/tools/clippy/tests/ui/lossy_float_literal.fixed
@@ -1,31 +1,55 @@
 #![warn(clippy::lossy_float_literal)]
 #![allow(overflowing_literals, unused)]
+#![feature(f128)]
+#![feature(f16)]
 
 fn main() {
     // Lossy whole-number float literals
+    let _: f16 = 4_097.0;
+    let _: f16 = 4_097.;
+    let _: f16 = 4_097.000;
+    let _ = 4_097f16;
+    let _: f16 = -4_097.0;
+
     let _: f32 = 16_777_216.0;
     let _: f32 = 16_777_220.0;
     let _: f32 = 16_777_220.0;
     let _: f32 = 16_777_220.0;
     let _ = 16_777_220_f32;
     let _: f32 = -16_777_220.0;
+
     let _: f64 = 9_007_199_254_740_992.0;
     let _: f64 = 9_007_199_254_740_992.0;
     let _: f64 = 9_007_199_254_740_992.0;
     let _ = 9_007_199_254_740_992_f64;
     let _: f64 = -9_007_199_254_740_992.0;
 
+    let _: f128 = 10_384_593_717_069_655_257_060_992_658_440_193.0;
+    let _: f128 = 10_384_593_717_069_655_257_060_992_658_440_193.;
+    let _: f128 = 10_384_593_717_069_655_257_060_992_658_440_193.00;
+    let _ = 10_384_593_717_069_655_257_060_992_658_440_193f128;
+    let _: f128 = -10_384_593_717_069_655_257_060_992_658_440_193.0;
+
     // Lossless whole number float literals
+    let _: f16 = 4_096.0;
+    let _: f16 = -4_096.0;
+
     let _: f32 = 16_777_216.0;
     let _: f32 = 16_777_218.0;
     let _: f32 = 16_777_220.0;
     let _: f32 = -16_777_216.0;
     let _: f32 = -16_777_220.0;
+
     let _: f64 = 16_777_217.0;
     let _: f64 = -16_777_217.0;
     let _: f64 = 9_007_199_254_740_992.0;
     let _: f64 = -9_007_199_254_740_992.0;
 
+    let _: f128 = 9_007_199_254_740_993.0;
+    let _: f128 = -9_007_199_254_740_993.0;
+    let _: f128 = 10_384_593_717_069_655_257_060_992_658_440_192.0;
+    let _: f128 = -10_384_593_717_069_655_257_060_992_658_440_192.0;
+
     // Ignored whole number float literals
     let _: f32 = 1e25;
     let _: f32 = 1E25;
diff --git a/src/tools/clippy/tests/ui/lossy_float_literal.rs b/src/tools/clippy/tests/ui/lossy_float_literal.rs
index 5abef3c442e..c84eef396d5 100644
--- a/src/tools/clippy/tests/ui/lossy_float_literal.rs
+++ b/src/tools/clippy/tests/ui/lossy_float_literal.rs
@@ -1,31 +1,55 @@
 #![warn(clippy::lossy_float_literal)]
 #![allow(overflowing_literals, unused)]
+#![feature(f128)]
+#![feature(f16)]
 
 fn main() {
     // Lossy whole-number float literals
+    let _: f16 = 4_097.0;
+    let _: f16 = 4_097.;
+    let _: f16 = 4_097.000;
+    let _ = 4_097f16;
+    let _: f16 = -4_097.0;
+
     let _: f32 = 16_777_217.0;
     let _: f32 = 16_777_219.0;
     let _: f32 = 16_777_219.;
     let _: f32 = 16_777_219.000;
     let _ = 16_777_219f32;
     let _: f32 = -16_777_219.0;
+
     let _: f64 = 9_007_199_254_740_993.0;
     let _: f64 = 9_007_199_254_740_993.;
     let _: f64 = 9_007_199_254_740_993.00;
     let _ = 9_007_199_254_740_993f64;
     let _: f64 = -9_007_199_254_740_993.0;
 
+    let _: f128 = 10_384_593_717_069_655_257_060_992_658_440_193.0;
+    let _: f128 = 10_384_593_717_069_655_257_060_992_658_440_193.;
+    let _: f128 = 10_384_593_717_069_655_257_060_992_658_440_193.00;
+    let _ = 10_384_593_717_069_655_257_060_992_658_440_193f128;
+    let _: f128 = -10_384_593_717_069_655_257_060_992_658_440_193.0;
+
     // Lossless whole number float literals
+    let _: f16 = 4_096.0;
+    let _: f16 = -4_096.0;
+
     let _: f32 = 16_777_216.0;
     let _: f32 = 16_777_218.0;
     let _: f32 = 16_777_220.0;
     let _: f32 = -16_777_216.0;
     let _: f32 = -16_777_220.0;
+
     let _: f64 = 16_777_217.0;
     let _: f64 = -16_777_217.0;
     let _: f64 = 9_007_199_254_740_992.0;
     let _: f64 = -9_007_199_254_740_992.0;
 
+    let _: f128 = 9_007_199_254_740_993.0;
+    let _: f128 = -9_007_199_254_740_993.0;
+    let _: f128 = 10_384_593_717_069_655_257_060_992_658_440_192.0;
+    let _: f128 = -10_384_593_717_069_655_257_060_992_658_440_192.0;
+
     // Ignored whole number float literals
     let _: f32 = 1e25;
     let _: f32 = 1E25;
diff --git a/src/tools/clippy/tests/ui/lossy_float_literal.stderr b/src/tools/clippy/tests/ui/lossy_float_literal.stderr
index 7904719141c..b5a07418734 100644
--- a/src/tools/clippy/tests/ui/lossy_float_literal.stderr
+++ b/src/tools/clippy/tests/ui/lossy_float_literal.stderr
@@ -1,5 +1,5 @@
 error: literal cannot be represented as the underlying type without loss of precision
-  --> tests/ui/lossy_float_literal.rs:6:18
+  --> tests/ui/lossy_float_literal.rs:14:18
    |
 LL |     let _: f32 = 16_777_217.0;
    |                  ^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_216.0`
@@ -8,61 +8,61 @@ LL |     let _: f32 = 16_777_217.0;
    = help: to override `-D warnings` add `#[allow(clippy::lossy_float_literal)]`
 
 error: literal cannot be represented as the underlying type without loss of precision
-  --> tests/ui/lossy_float_literal.rs:7:18
+  --> tests/ui/lossy_float_literal.rs:15:18
    |
 LL |     let _: f32 = 16_777_219.0;
    |                  ^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0`
 
 error: literal cannot be represented as the underlying type without loss of precision
-  --> tests/ui/lossy_float_literal.rs:8:18
+  --> tests/ui/lossy_float_literal.rs:16:18
    |
 LL |     let _: f32 = 16_777_219.;
    |                  ^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0`
 
 error: literal cannot be represented as the underlying type without loss of precision
-  --> tests/ui/lossy_float_literal.rs:9:18
+  --> tests/ui/lossy_float_literal.rs:17:18
    |
 LL |     let _: f32 = 16_777_219.000;
    |                  ^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0`
 
 error: literal cannot be represented as the underlying type without loss of precision
-  --> tests/ui/lossy_float_literal.rs:10:13
+  --> tests/ui/lossy_float_literal.rs:18:13
    |
 LL |     let _ = 16_777_219f32;
    |             ^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220_f32`
 
 error: literal cannot be represented as the underlying type without loss of precision
-  --> tests/ui/lossy_float_literal.rs:11:19
+  --> tests/ui/lossy_float_literal.rs:19:19
    |
 LL |     let _: f32 = -16_777_219.0;
    |                   ^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0`
 
 error: literal cannot be represented as the underlying type without loss of precision
-  --> tests/ui/lossy_float_literal.rs:12:18
+  --> tests/ui/lossy_float_literal.rs:21:18
    |
 LL |     let _: f64 = 9_007_199_254_740_993.0;
    |                  ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0`
 
 error: literal cannot be represented as the underlying type without loss of precision
-  --> tests/ui/lossy_float_literal.rs:13:18
+  --> tests/ui/lossy_float_literal.rs:22:18
    |
 LL |     let _: f64 = 9_007_199_254_740_993.;
    |                  ^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0`
 
 error: literal cannot be represented as the underlying type without loss of precision
-  --> tests/ui/lossy_float_literal.rs:14:18
+  --> tests/ui/lossy_float_literal.rs:23:18
    |
 LL |     let _: f64 = 9_007_199_254_740_993.00;
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0`
 
 error: literal cannot be represented as the underlying type without loss of precision
-  --> tests/ui/lossy_float_literal.rs:15:13
+  --> tests/ui/lossy_float_literal.rs:24:13
    |
 LL |     let _ = 9_007_199_254_740_993f64;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992_f64`
 
 error: literal cannot be represented as the underlying type without loss of precision
-  --> tests/ui/lossy_float_literal.rs:16:19
+  --> tests/ui/lossy_float_literal.rs:25:19
    |
 LL |     let _: f64 = -9_007_199_254_740_993.0;
    |                   ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0`
diff --git a/src/tools/clippy/tests/ui/macro_use_imports.fixed b/src/tools/clippy/tests/ui/macro_use_imports.fixed
index 46c053b779e..38ed5a957e7 100644
--- a/src/tools/clippy/tests/ui/macro_use_imports.fixed
+++ b/src/tools/clippy/tests/ui/macro_use_imports.fixed
@@ -4,7 +4,6 @@
 
 //@ignore-32bit
 
-#![feature(lint_reasons)]
 #![allow(unused_imports, unreachable_code, unused_variables, dead_code, unused_attributes)]
 #![allow(clippy::single_component_path_imports)]
 #![warn(clippy::macro_use_imports)]
diff --git a/src/tools/clippy/tests/ui/macro_use_imports.rs b/src/tools/clippy/tests/ui/macro_use_imports.rs
index 47f5c9bf884..ae6cc16ed27 100644
--- a/src/tools/clippy/tests/ui/macro_use_imports.rs
+++ b/src/tools/clippy/tests/ui/macro_use_imports.rs
@@ -4,7 +4,6 @@
 
 //@ignore-32bit
 
-#![feature(lint_reasons)]
 #![allow(unused_imports, unreachable_code, unused_variables, dead_code, unused_attributes)]
 #![allow(clippy::single_component_path_imports)]
 #![warn(clippy::macro_use_imports)]
diff --git a/src/tools/clippy/tests/ui/macro_use_imports.stderr b/src/tools/clippy/tests/ui/macro_use_imports.stderr
index a3733b1c0c9..ea0670d3666 100644
--- a/src/tools/clippy/tests/ui/macro_use_imports.stderr
+++ b/src/tools/clippy/tests/ui/macro_use_imports.stderr
@@ -1,5 +1,5 @@
 error: `macro_use` attributes are no longer needed in the Rust 2018 edition
-  --> tests/ui/macro_use_imports.rs:19:5
+  --> tests/ui/macro_use_imports.rs:18:5
    |
 LL |     #[macro_use]
    |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};`
@@ -8,19 +8,19 @@ LL |     #[macro_use]
    = help: to override `-D warnings` add `#[allow(clippy::macro_use_imports)]`
 
 error: `macro_use` attributes are no longer needed in the Rust 2018 edition
-  --> tests/ui/macro_use_imports.rs:23:5
+  --> tests/ui/macro_use_imports.rs:22:5
    |
 LL |     #[macro_use]
    |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::mut_mut, inner::try_err};`
 
 error: `macro_use` attributes are no longer needed in the Rust 2018 edition
-  --> tests/ui/macro_use_imports.rs:25:5
+  --> tests/ui/macro_use_imports.rs:24:5
    |
 LL |     #[macro_use]
    |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;`
 
 error: `macro_use` attributes are no longer needed in the Rust 2018 edition
-  --> tests/ui/macro_use_imports.rs:21:5
+  --> tests/ui/macro_use_imports.rs:20:5
    |
 LL |     #[macro_use]
    |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;`
diff --git a/src/tools/clippy/tests/ui/macro_use_imports_expect.rs b/src/tools/clippy/tests/ui/macro_use_imports_expect.rs
index b9677851b92..df6d5b9fbab 100644
--- a/src/tools/clippy/tests/ui/macro_use_imports_expect.rs
+++ b/src/tools/clippy/tests/ui/macro_use_imports_expect.rs
@@ -3,7 +3,6 @@
 //@aux-build:proc_macro_derive.rs
 //@ignore-32bit
 
-#![feature(lint_reasons)]
 #![allow(unused_imports, unreachable_code, unused_variables, dead_code, unused_attributes)]
 #![allow(clippy::single_component_path_imports)]
 #![warn(clippy::macro_use_imports)]
diff --git a/src/tools/clippy/tests/ui/manual_float_methods.rs b/src/tools/clippy/tests/ui/manual_float_methods.rs
index 80781ecda72..ee3daa12834 100644
--- a/src/tools/clippy/tests/ui/manual_float_methods.rs
+++ b/src/tools/clippy/tests/ui/manual_float_methods.rs
@@ -3,6 +3,8 @@
 #![allow(clippy::needless_if, unused)]
 #![warn(clippy::manual_is_infinite, clippy::manual_is_finite)]
 
+// FIXME(f16_f128): add tests for these types once constants are available
+
 #[macro_use]
 extern crate proc_macros;
 
diff --git a/src/tools/clippy/tests/ui/manual_float_methods.stderr b/src/tools/clippy/tests/ui/manual_float_methods.stderr
index 930df0b97cb..70057620a4a 100644
--- a/src/tools/clippy/tests/ui/manual_float_methods.stderr
+++ b/src/tools/clippy/tests/ui/manual_float_methods.stderr
@@ -1,5 +1,5 @@
 error: manually checking if a float is infinite
-  --> tests/ui/manual_float_methods.rs:22:8
+  --> tests/ui/manual_float_methods.rs:24:8
    |
 LL |     if x == f32::INFINITY || x == f32::NEG_INFINITY {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()`
@@ -8,7 +8,7 @@ LL |     if x == f32::INFINITY || x == f32::NEG_INFINITY {}
    = help: to override `-D warnings` add `#[allow(clippy::manual_is_infinite)]`
 
 error: manually checking if a float is finite
-  --> tests/ui/manual_float_methods.rs:23:8
+  --> tests/ui/manual_float_methods.rs:25:8
    |
 LL |     if x != f32::INFINITY && x != f32::NEG_INFINITY {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -29,13 +29,13 @@ LL |     if !x.is_infinite() {}
    |        ~~~~~~~~~~~~~~~~
 
 error: manually checking if a float is infinite
-  --> tests/ui/manual_float_methods.rs:24:8
+  --> tests/ui/manual_float_methods.rs:26:8
    |
 LL |     if x == INFINITE || x == NEG_INFINITE {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()`
 
 error: manually checking if a float is finite
-  --> tests/ui/manual_float_methods.rs:25:8
+  --> tests/ui/manual_float_methods.rs:27:8
    |
 LL |     if x != INFINITE && x != NEG_INFINITE {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -54,13 +54,13 @@ LL |     if !x.is_infinite() {}
    |        ~~~~~~~~~~~~~~~~
 
 error: manually checking if a float is infinite
-  --> tests/ui/manual_float_methods.rs:27:8
+  --> tests/ui/manual_float_methods.rs:29:8
    |
 LL |     if x == f64::INFINITY || x == f64::NEG_INFINITY {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()`
 
 error: manually checking if a float is finite
-  --> tests/ui/manual_float_methods.rs:28:8
+  --> tests/ui/manual_float_methods.rs:30:8
    |
 LL |     if x != f64::INFINITY && x != f64::NEG_INFINITY {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/manual_inspect.fixed b/src/tools/clippy/tests/ui/manual_inspect.fixed
new file mode 100644
index 00000000000..0e1b8fe3edb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_inspect.fixed
@@ -0,0 +1,174 @@
+#![warn(clippy::manual_inspect)]
+#![allow(clippy::no_effect, clippy::op_ref)]
+
+fn main() {
+    let _ = Some(0).inspect(|&x| {
+        println!("{}", x);
+    });
+
+    let _ = Some(0).inspect(|&x| {
+        println!("{x}");
+    });
+
+    let _ = Some(0).inspect(|&x| {
+        println!("{}", x * 5 + 1);
+    });
+
+    let _ = Some(0).inspect(|&x| {
+        if x == 0 {
+            panic!();
+        }
+    });
+
+    let _ = Some(0).inspect(|&x| {
+        if &x == &0 {
+            let _y = x;
+            panic!();
+        }
+    });
+
+    let _ = Some(0).map(|x| {
+        let y = x + 1;
+        if y > 5 {
+            return y;
+        }
+        x
+    });
+
+    {
+        #[derive(PartialEq)]
+        struct Foo(i32);
+
+        let _ = Some(Foo(0)).map(|x| {
+            if x == Foo(0) {
+                panic!();
+            }
+            x
+        });
+
+        let _ = Some(Foo(0)).map(|x| {
+            if &x == &Foo(0) {
+                let _y = x;
+                panic!();
+            }
+            x
+        });
+    }
+
+    {
+        macro_rules! maybe_ret {
+            ($e:expr) => {
+                if $e == 0 {
+                    return $e;
+                }
+            };
+        }
+
+        let _ = Some(0).map(|x| {
+            maybe_ret!(x);
+            x
+        });
+    }
+
+    let _ = Some((String::new(), 0u32)).inspect(|x| {
+        if x.1 == 0 {
+            let _x = x.1;
+            panic!();
+        }
+    });
+
+    let _ = Some((String::new(), 0u32)).map(|x| {
+        if x.1 == 0 {
+            let _x = x.0;
+            panic!();
+        }
+        x
+    });
+
+    let _ = Some(String::new()).map(|x| {
+        if x.is_empty() {
+            let _ = || {
+                let _x = x;
+            };
+            panic!();
+        }
+        x
+    });
+
+    let _ = Some(String::new()).inspect(|x| {
+        if x.is_empty() {
+            let _ = || {
+                let _x = x;
+            };
+            return;
+        }
+        println!("test");
+    });
+
+    let _ = Some(0).inspect(|&x| {
+        if x == 0 {
+            let _ = || {
+                let _x = x;
+            };
+            panic!();
+        }
+    });
+
+    {
+        use core::cell::Cell;
+        #[derive(Debug)]
+        struct Cell2(core::cell::Cell<u32>);
+
+        let _ = Some(Cell2(Cell::new(0u32))).inspect(|x| {
+            x.0.set(1);
+        });
+
+        let _ = Some(Cell2(Cell::new(0u32))).map(|x| {
+            let y = &x;
+            if x.0.get() == 0 {
+                y.0.set(1)
+            } else {
+                println!("{x:?}");
+            }
+            x
+        });
+    }
+
+    let _: Result<_, ()> = Ok(0).inspect(|&x| {
+        println!("{}", x);
+    });
+
+    let _: Result<(), _> = Err(0).inspect_err(|&x| {
+        println!("{}", x);
+    });
+
+    let _ = [0]
+        .into_iter()
+        .inspect(|&x| {
+            println!("{}", x);
+        })
+        .count();
+
+    {
+        struct S<T>(T);
+        impl<T> S<T> {
+            fn map<U>(self, f: impl FnOnce(T) -> U) -> S<U> {
+                S(f(self.0))
+            }
+
+            fn map_err<U>(self, f: impl FnOnce(T) -> U) -> S<U> {
+                S(f(self.0))
+            }
+        }
+
+        let _ = S(0).map(|x| {
+            println!("{}", x);
+            x
+        });
+
+        let _ = S(0).map_err(|x| {
+            println!("{}", x);
+            x
+        });
+    }
+}
diff --git a/src/tools/clippy/tests/ui/manual_inspect.rs b/src/tools/clippy/tests/ui/manual_inspect.rs
new file mode 100644
index 00000000000..94cdfe39140
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_inspect.rs
@@ -0,0 +1,186 @@
+#![warn(clippy::manual_inspect)]
+#![allow(clippy::no_effect, clippy::op_ref)]
+
+fn main() {
+    let _ = Some(0).map(|x| {
+        println!("{}", x);
+        x
+    });
+
+    let _ = Some(0).map(|x| {
+        println!("{x}");
+        x
+    });
+
+    let _ = Some(0).map(|x| {
+        println!("{}", x * 5 + 1);
+        x
+    });
+
+    let _ = Some(0).map(|x| {
+        if x == 0 {
+            panic!();
+        }
+        x
+    });
+
+    let _ = Some(0).map(|x| {
+        if &x == &0 {
+            let _y = x;
+            panic!();
+        }
+        x
+    });
+
+    let _ = Some(0).map(|x| {
+        let y = x + 1;
+        if y > 5 {
+            return y;
+        }
+        x
+    });
+
+    {
+        #[derive(PartialEq)]
+        struct Foo(i32);
+
+        let _ = Some(Foo(0)).map(|x| {
+            if x == Foo(0) {
+                panic!();
+            }
+            x
+        });
+
+        let _ = Some(Foo(0)).map(|x| {
+            if &x == &Foo(0) {
+                let _y = x;
+                panic!();
+            }
+            x
+        });
+    }
+
+    {
+        macro_rules! maybe_ret {
+            ($e:expr) => {
+                if $e == 0 {
+                    return $e;
+                }
+            };
+        }
+
+        let _ = Some(0).map(|x| {
+            maybe_ret!(x);
+            x
+        });
+    }
+
+    let _ = Some((String::new(), 0u32)).map(|x| {
+        if x.1 == 0 {
+            let _x = x.1;
+            panic!();
+        }
+        x
+    });
+
+    let _ = Some((String::new(), 0u32)).map(|x| {
+        if x.1 == 0 {
+            let _x = x.0;
+            panic!();
+        }
+        x
+    });
+
+    let _ = Some(String::new()).map(|x| {
+        if x.is_empty() {
+            let _ = || {
+                let _x = x;
+            };
+            panic!();
+        }
+        x
+    });
+
+    let _ = Some(String::new()).map(|x| {
+        if x.is_empty() {
+            let _ = || {
+                let _x = &x;
+            };
+            return x;
+        }
+        println!("test");
+        x
+    });
+
+    let _ = Some(0).map(|x| {
+        if x == 0 {
+            let _ = || {
+                let _x = x;
+            };
+            panic!();
+        }
+        x
+    });
+
+    {
+        use core::cell::Cell;
+        #[derive(Debug)]
+        struct Cell2(core::cell::Cell<u32>);
+
+        let _ = Some(Cell2(Cell::new(0u32))).map(|x| {
+            x.0.set(1);
+            x
+        });
+
+        let _ = Some(Cell2(Cell::new(0u32))).map(|x| {
+            let y = &x;
+            if x.0.get() == 0 {
+                y.0.set(1)
+            } else {
+                println!("{x:?}");
+            }
+            x
+        });
+    }
+
+    let _: Result<_, ()> = Ok(0).map(|x| {
+        println!("{}", x);
+        x
+    });
+
+    let _: Result<(), _> = Err(0).map_err(|x| {
+        println!("{}", x);
+        x
+    });
+
+    let _ = [0]
+        .into_iter()
+        .map(|x| {
+            println!("{}", x);
+            x
+        })
+        .count();
+
+    {
+        struct S<T>(T);
+        impl<T> S<T> {
+            fn map<U>(self, f: impl FnOnce(T) -> U) -> S<U> {
+                S(f(self.0))
+            }
+
+            fn map_err<U>(self, f: impl FnOnce(T) -> U) -> S<U> {
+                S(f(self.0))
+            }
+        }
+
+        let _ = S(0).map(|x| {
+            println!("{}", x);
+            x
+        });
+
+        let _ = S(0).map_err(|x| {
+            println!("{}", x);
+            x
+        });
+    }
+}
diff --git a/src/tools/clippy/tests/ui/manual_inspect.stderr b/src/tools/clippy/tests/ui/manual_inspect.stderr
new file mode 100644
index 00000000000..8548c0cd294
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_inspect.stderr
@@ -0,0 +1,182 @@
+error: 
+  --> tests/ui/manual_inspect.rs:5:21
+   |
+LL |     let _ = Some(0).map(|x| {
+   |                     ^^^
+   |
+   = note: `-D clippy::manual-inspect` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::manual_inspect)]`
+help: try
+   |
+LL ~     let _ = Some(0).inspect(|&x| {
+LL ~         println!("{}", x);
+   |
+
+error: 
+  --> tests/ui/manual_inspect.rs:10:21
+   |
+LL |     let _ = Some(0).map(|x| {
+   |                     ^^^
+   |
+help: try
+   |
+LL ~     let _ = Some(0).inspect(|&x| {
+LL ~         println!("{x}");
+   |
+
+error: 
+  --> tests/ui/manual_inspect.rs:15:21
+   |
+LL |     let _ = Some(0).map(|x| {
+   |                     ^^^
+   |
+help: try
+   |
+LL ~     let _ = Some(0).inspect(|&x| {
+LL ~         println!("{}", x * 5 + 1);
+   |
+
+error: 
+  --> tests/ui/manual_inspect.rs:20:21
+   |
+LL |     let _ = Some(0).map(|x| {
+   |                     ^^^
+   |
+help: try
+   |
+LL ~     let _ = Some(0).inspect(|&x| {
+LL |         if x == 0 {
+LL |             panic!();
+LL ~         }
+   |
+
+error: 
+  --> tests/ui/manual_inspect.rs:27:21
+   |
+LL |     let _ = Some(0).map(|x| {
+   |                     ^^^
+   |
+help: try
+   |
+LL ~     let _ = Some(0).inspect(|&x| {
+LL |         if &x == &0 {
+LL |             let _y = x;
+LL |             panic!();
+LL ~         }
+   |
+
+error: 
+  --> tests/ui/manual_inspect.rs:78:41
+   |
+LL |     let _ = Some((String::new(), 0u32)).map(|x| {
+   |                                         ^^^
+   |
+help: try
+   |
+LL ~     let _ = Some((String::new(), 0u32)).inspect(|x| {
+LL |         if x.1 == 0 {
+LL |             let _x = x.1;
+LL |             panic!();
+LL ~         }
+   |
+
+error: 
+  --> tests/ui/manual_inspect.rs:104:33
+   |
+LL |     let _ = Some(String::new()).map(|x| {
+   |                                 ^^^
+   |
+help: try
+   |
+LL ~     let _ = Some(String::new()).inspect(|x| {
+LL |         if x.is_empty() {
+LL |             let _ = || {
+LL ~                 let _x = x;
+LL |             };
+LL ~             return;
+LL |         }
+LL ~         println!("test");
+   |
+
+error: 
+  --> tests/ui/manual_inspect.rs:115:21
+   |
+LL |     let _ = Some(0).map(|x| {
+   |                     ^^^
+   |
+help: try
+   |
+LL ~     let _ = Some(0).inspect(|&x| {
+LL |         if x == 0 {
+...
+LL |             panic!();
+LL ~         }
+   |
+
+error: 
+  --> tests/ui/manual_inspect.rs:130:46
+   |
+LL |         let _ = Some(Cell2(Cell::new(0u32))).map(|x| {
+   |                                              ^^^
+   |
+help: try
+   |
+LL ~         let _ = Some(Cell2(Cell::new(0u32))).inspect(|x| {
+LL ~             x.0.set(1);
+   |
+
+error: 
+  --> tests/ui/manual_inspect.rs:146:34
+   |
+LL |     let _: Result<_, ()> = Ok(0).map(|x| {
+   |                                  ^^^
+   |
+help: try
+   |
+LL ~     let _: Result<_, ()> = Ok(0).inspect(|&x| {
+LL ~         println!("{}", x);
+   |
+
+error: 
+  --> tests/ui/manual_inspect.rs:151:35
+   |
+LL |     let _: Result<(), _> = Err(0).map_err(|x| {
+   |                                   ^^^^^^^
+   |
+help: try
+   |
+LL ~     let _: Result<(), _> = Err(0).inspect_err(|&x| {
+LL ~         println!("{}", x);
+   |
+
+error: this call to `map()` won't have an effect on the call to `count()`
+  --> tests/ui/manual_inspect.rs:156:13
+   |
+LL |       let _ = [0]
+   |  _____________^
+LL | |         .into_iter()
+LL | |         .map(|x| {
+LL | |             println!("{}", x);
+LL | |             x
+LL | |         })
+LL | |         .count();
+   | |________________^
+   |
+   = help: make sure you did not confuse `map` with `filter`, `for_each` or `inspect`
+   = note: `-D clippy::suspicious-map` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::suspicious_map)]`
+
+error: 
+  --> tests/ui/manual_inspect.rs:158:10
+   |
+LL |         .map(|x| {
+   |          ^^^
+   |
+help: try
+   |
+LL ~         .inspect(|&x| {
+LL ~             println!("{}", x);
+   |
+
+error: aborting due to 13 previous errors
+
diff --git a/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.rs b/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.rs
index eb387532031..31c3cc80137 100644
--- a/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.rs
+++ b/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.rs
@@ -1,4 +1,3 @@
-#![feature(lint_reasons)]
 #![warn(clippy::manual_non_exhaustive)]
 #![allow(unused)]
 //@no-rustfix
diff --git a/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr b/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr
index ee43b8ddc02..dc669568dd2 100644
--- a/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr
+++ b/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr
@@ -1,5 +1,5 @@
 error: this seems like a manual implementation of the non-exhaustive pattern
-  --> tests/ui/manual_non_exhaustive_enum.rs:5:1
+  --> tests/ui/manual_non_exhaustive_enum.rs:4:1
    |
 LL |   enum E {
    |   ^-----
@@ -15,7 +15,7 @@ LL | | }
    | |_^
    |
 help: remove this variant
-  --> tests/ui/manual_non_exhaustive_enum.rs:10:5
+  --> tests/ui/manual_non_exhaustive_enum.rs:9:5
    |
 LL |     _C,
    |     ^^
@@ -23,7 +23,7 @@ LL |     _C,
    = help: to override `-D warnings` add `#[allow(clippy::manual_non_exhaustive)]`
 
 error: this seems like a manual implementation of the non-exhaustive pattern
-  --> tests/ui/manual_non_exhaustive_enum.rs:30:1
+  --> tests/ui/manual_non_exhaustive_enum.rs:29:1
    |
 LL |   enum NoUnderscore {
    |   ^----------------
@@ -38,7 +38,7 @@ LL | | }
    | |_^
    |
 help: remove this variant
-  --> tests/ui/manual_non_exhaustive_enum.rs:34:5
+  --> tests/ui/manual_non_exhaustive_enum.rs:33:5
    |
 LL |     C,
    |     ^
diff --git a/src/tools/clippy/tests/ui/manual_pattern_char_comparison.fixed b/src/tools/clippy/tests/ui/manual_pattern_char_comparison.fixed
index 588226b87e8..03e621d95ba 100644
--- a/src/tools/clippy/tests/ui/manual_pattern_char_comparison.fixed
+++ b/src/tools/clippy/tests/ui/manual_pattern_char_comparison.fixed
@@ -47,3 +47,15 @@ fn main() {
     }
     "".find(|c| m!(c));
 }
+
+#[clippy::msrv = "1.57"]
+fn msrv_1_57() {
+    let sentence = "Hello, world!";
+    sentence.trim_end_matches(|c: char| c == '.' || c == ',' || c == '!' || c == '?');
+}
+
+#[clippy::msrv = "1.58"]
+fn msrv_1_58() {
+    let sentence = "Hello, world!";
+    sentence.trim_end_matches(['.', ',', '!', '?']);
+}
diff --git a/src/tools/clippy/tests/ui/manual_pattern_char_comparison.rs b/src/tools/clippy/tests/ui/manual_pattern_char_comparison.rs
index 5078f3ee27f..43e883cd325 100644
--- a/src/tools/clippy/tests/ui/manual_pattern_char_comparison.rs
+++ b/src/tools/clippy/tests/ui/manual_pattern_char_comparison.rs
@@ -47,3 +47,15 @@ fn main() {
     }
     "".find(|c| m!(c));
 }
+
+#[clippy::msrv = "1.57"]
+fn msrv_1_57() {
+    let sentence = "Hello, world!";
+    sentence.trim_end_matches(|c: char| c == '.' || c == ',' || c == '!' || c == '?');
+}
+
+#[clippy::msrv = "1.58"]
+fn msrv_1_58() {
+    let sentence = "Hello, world!";
+    sentence.trim_end_matches(|c: char| c == '.' || c == ',' || c == '!' || c == '?');
+}
diff --git a/src/tools/clippy/tests/ui/manual_pattern_char_comparison.stderr b/src/tools/clippy/tests/ui/manual_pattern_char_comparison.stderr
index b6b51794a11..f185d7c8f67 100644
--- a/src/tools/clippy/tests/ui/manual_pattern_char_comparison.stderr
+++ b/src/tools/clippy/tests/ui/manual_pattern_char_comparison.stderr
@@ -55,5 +55,11 @@ error: this manual char comparison can be written more succinctly
 LL |     sentence.find(|c| c == '🎈');
    |                   ^^^^^^^^^^^^^ help: consider using a `char`: `'🎈'`
 
-error: aborting due to 9 previous errors
+error: this manual char comparison can be written more succinctly
+  --> tests/ui/manual_pattern_char_comparison.rs:60:31
+   |
+LL |     sentence.trim_end_matches(|c: char| c == '.' || c == ',' || c == '!' || c == '?');
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using an array of `char`: `['.', ',', '!', '?']`
+
+error: aborting due to 10 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_split_once.stderr b/src/tools/clippy/tests/ui/manual_split_once.stderr
index b4e51f473cf..c5c9be3ac63 100644
--- a/src/tools/clippy/tests/ui/manual_split_once.stderr
+++ b/src/tools/clippy/tests/ui/manual_split_once.stderr
@@ -96,12 +96,10 @@ LL |     let (l, r) = "a.b.c".split_once('.').unwrap();
 help: remove the `iter` usages
    |
 LL -     let l = iter.next().unwrap();
-LL +     
    |
 help: remove the `iter` usages
    |
 LL -     let r = iter.next().unwrap();
-LL +     
    |
 
 error: manual implementation of `split_once`
@@ -121,12 +119,10 @@ LL |     let (l, r) = "a.b.c".split_once('.')?;
 help: remove the `iter` usages
    |
 LL -     let l = iter.next()?;
-LL +     
    |
 help: remove the `iter` usages
    |
 LL -     let r = iter.next()?;
-LL +     
    |
 
 error: manual implementation of `rsplit_once`
@@ -146,12 +142,10 @@ LL |     let (l, r) = "a.b.c".rsplit_once('.').unwrap();
 help: remove the `iter` usages
    |
 LL -     let r = iter.next().unwrap();
-LL +     
    |
 help: remove the `iter` usages
    |
 LL -     let l = iter.next().unwrap();
-LL +     
    |
 
 error: manual implementation of `rsplit_once`
@@ -171,12 +165,10 @@ LL |     let (l, r) = "a.b.c".rsplit_once('.')?;
 help: remove the `iter` usages
    |
 LL -     let r = iter.next()?;
-LL +     
    |
 help: remove the `iter` usages
    |
 LL -     let l = iter.next()?;
-LL +     
    |
 
 error: manual implementation of `split_once`
@@ -202,12 +194,10 @@ LL |     let (a, b) = "a.b.c".split_once('.').unwrap();
 help: remove the `iter` usages
    |
 LL -     let a = iter.next().unwrap();
-LL +     
    |
 help: remove the `iter` usages
    |
 LL -     let b = iter.next().unwrap();
-LL +     
    |
 
 error: aborting due to 19 previous errors
diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or.fixed b/src/tools/clippy/tests/ui/manual_unwrap_or.fixed
index dffd44b6a7c..74afa00e12f 100644
--- a/src/tools/clippy/tests/ui/manual_unwrap_or.fixed
+++ b/src/tools/clippy/tests/ui/manual_unwrap_or.fixed
@@ -68,6 +68,32 @@ fn option_unwrap_or() {
         Some(s) => s,
         None => &format!("{} {}!", "hello", "world"),
     };
+
+    Some(1).unwrap_or(42);
+
+    //don't lint
+    if let Some(x) = Some(1) {
+        x + 1
+    } else {
+        42
+    };
+    if let Some(x) = Some(1) {
+        x
+    } else {
+        return;
+    };
+    for j in 0..4 {
+        if let Some(x) = Some(j) {
+            x
+        } else {
+            continue;
+        };
+        if let Some(x) = Some(j) {
+            x
+        } else {
+            break;
+        };
+    }
 }
 
 fn result_unwrap_or() {
@@ -138,6 +164,32 @@ fn result_unwrap_or() {
         Ok(s) => s,
         Err(s) => "Bob",
     };
+
+    Ok::<i32, i32>(1).unwrap_or(42);
+
+    //don't lint
+    if let Ok(x) = Ok::<i32, i32>(1) {
+        x + 1
+    } else {
+        42
+    };
+    if let Ok(x) = Ok::<i32, i32>(1) {
+        x
+    } else {
+        return;
+    };
+    for j in 0..4 {
+        if let Ok(x) = Ok::<i32, i32>(j) {
+            x
+        } else {
+            continue;
+        };
+        if let Ok(x) = Ok::<i32, i32>(j) {
+            x
+        } else {
+            break;
+        };
+    }
 }
 
 // don't lint in const fn
diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or.rs b/src/tools/clippy/tests/ui/manual_unwrap_or.rs
index 67427132c1a..2d01b8ceaaa 100644
--- a/src/tools/clippy/tests/ui/manual_unwrap_or.rs
+++ b/src/tools/clippy/tests/ui/manual_unwrap_or.rs
@@ -83,6 +83,36 @@ fn option_unwrap_or() {
         Some(s) => s,
         None => &format!("{} {}!", "hello", "world"),
     };
+
+    if let Some(x) = Some(1) {
+        x
+    } else {
+        42
+    };
+
+    //don't lint
+    if let Some(x) = Some(1) {
+        x + 1
+    } else {
+        42
+    };
+    if let Some(x) = Some(1) {
+        x
+    } else {
+        return;
+    };
+    for j in 0..4 {
+        if let Some(x) = Some(j) {
+            x
+        } else {
+            continue;
+        };
+        if let Some(x) = Some(j) {
+            x
+        } else {
+            break;
+        };
+    }
 }
 
 fn result_unwrap_or() {
@@ -177,6 +207,36 @@ fn result_unwrap_or() {
         Ok(s) => s,
         Err(s) => "Bob",
     };
+
+    if let Ok(x) = Ok::<i32, i32>(1) {
+        x
+    } else {
+        42
+    };
+
+    //don't lint
+    if let Ok(x) = Ok::<i32, i32>(1) {
+        x + 1
+    } else {
+        42
+    };
+    if let Ok(x) = Ok::<i32, i32>(1) {
+        x
+    } else {
+        return;
+    };
+    for j in 0..4 {
+        if let Ok(x) = Ok::<i32, i32>(j) {
+            x
+        } else {
+            continue;
+        };
+        if let Ok(x) = Ok::<i32, i32>(j) {
+            x
+        } else {
+            break;
+        };
+    }
 }
 
 // don't lint in const fn
diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or.stderr b/src/tools/clippy/tests/ui/manual_unwrap_or.stderr
index 33a099680ce..c93a8952a08 100644
--- a/src/tools/clippy/tests/ui/manual_unwrap_or.stderr
+++ b/src/tools/clippy/tests/ui/manual_unwrap_or.stderr
@@ -58,8 +58,18 @@ LL | |         None => "Alice",
 LL | |     };
    | |_____^ help: replace with: `Some("Bob").unwrap_or("Alice")`
 
+error: this pattern reimplements `Option::unwrap_or`
+  --> tests/ui/manual_unwrap_or.rs:87:5
+   |
+LL | /     if let Some(x) = Some(1) {
+LL | |         x
+LL | |     } else {
+LL | |         42
+LL | |     };
+   | |_____^ help: replace with: `Some(1).unwrap_or(42)`
+
 error: this pattern reimplements `Result::unwrap_or`
-  --> tests/ui/manual_unwrap_or.rs:90:5
+  --> tests/ui/manual_unwrap_or.rs:120:5
    |
 LL | /     match Ok::<i32, &str>(1) {
 LL | |         Ok(i) => i,
@@ -68,7 +78,7 @@ LL | |     };
    | |_____^ help: replace with: `Ok::<i32, &str>(1).unwrap_or(42)`
 
 error: this pattern reimplements `Result::unwrap_or`
-  --> tests/ui/manual_unwrap_or.rs:97:5
+  --> tests/ui/manual_unwrap_or.rs:127:5
    |
 LL | /     match a {
 LL | |         Ok(i) => i,
@@ -77,7 +87,7 @@ LL | |     };
    | |_____^ help: replace with: `a.unwrap_or(42)`
 
 error: this pattern reimplements `Result::unwrap_or`
-  --> tests/ui/manual_unwrap_or.rs:103:5
+  --> tests/ui/manual_unwrap_or.rs:133:5
    |
 LL | /     match Ok(1) as Result<i32, &str> {
 LL | |         Ok(i) => i,
@@ -86,7 +96,7 @@ LL | |     };
    | |_____^ help: replace with: `(Ok(1) as Result<i32, &str>).unwrap_or(42)`
 
 error: this pattern reimplements `Option::unwrap_or`
-  --> tests/ui/manual_unwrap_or.rs:116:5
+  --> tests/ui/manual_unwrap_or.rs:146:5
    |
 LL | /     match s.method() {
 LL | |         Some(i) => i,
@@ -95,7 +105,7 @@ LL | |     };
    | |_____^ help: replace with: `s.method().unwrap_or(42)`
 
 error: this pattern reimplements `Result::unwrap_or`
-  --> tests/ui/manual_unwrap_or.rs:122:5
+  --> tests/ui/manual_unwrap_or.rs:152:5
    |
 LL | /     match Ok::<i32, &str>(1) {
 LL | |         Err(_) => 42,
@@ -104,7 +114,7 @@ LL | |     };
    | |_____^ help: replace with: `Ok::<i32, &str>(1).unwrap_or(42)`
 
 error: this pattern reimplements `Result::unwrap_or`
-  --> tests/ui/manual_unwrap_or.rs:128:5
+  --> tests/ui/manual_unwrap_or.rs:158:5
    |
 LL | /     match Ok::<i32, &str>(1) {
 LL | |         Ok(i) => i,
@@ -113,7 +123,7 @@ LL | |     };
    | |_____^ help: replace with: `Ok::<i32, &str>(1).unwrap_or(1 + 42)`
 
 error: this pattern reimplements `Result::unwrap_or`
-  --> tests/ui/manual_unwrap_or.rs:135:5
+  --> tests/ui/manual_unwrap_or.rs:165:5
    |
 LL | /     match Ok::<i32, &str>(1) {
 LL | |         Ok(i) => i,
@@ -134,7 +144,7 @@ LL ~     });
    |
 
 error: this pattern reimplements `Result::unwrap_or`
-  --> tests/ui/manual_unwrap_or.rs:145:5
+  --> tests/ui/manual_unwrap_or.rs:175:5
    |
 LL | /     match Ok::<&str, &str>("Bob") {
 LL | |         Ok(i) => i,
@@ -142,8 +152,18 @@ LL | |         Err(_) => "Alice",
 LL | |     };
    | |_____^ help: replace with: `Ok::<&str, &str>("Bob").unwrap_or("Alice")`
 
+error: this pattern reimplements `Result::unwrap_or`
+  --> tests/ui/manual_unwrap_or.rs:211:5
+   |
+LL | /     if let Ok(x) = Ok::<i32, i32>(1) {
+LL | |         x
+LL | |     } else {
+LL | |         42
+LL | |     };
+   | |_____^ help: replace with: `Ok::<i32, i32>(1).unwrap_or(42)`
+
 error: this pattern reimplements `Option::unwrap_or`
-  --> tests/ui/manual_unwrap_or.rs:205:17
+  --> tests/ui/manual_unwrap_or.rs:265:17
    |
 LL |           let _ = match some_macro!() {
    |  _________________^
@@ -152,5 +172,5 @@ LL | |             None => 0,
 LL | |         };
    | |_________^ help: replace with: `some_macro!().unwrap_or(0)`
 
-error: aborting due to 14 previous errors
+error: aborting due to 16 previous errors
 
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 663de1a5f06..832376fa5af 100644
--- a/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed
+++ b/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed
@@ -1,5 +1,5 @@
 #![warn(clippy::manual_unwrap_or_default)]
-#![allow(clippy::unnecessary_literal_unwrap)]
+#![allow(clippy::unnecessary_literal_unwrap, clippy::manual_unwrap_or)]
 
 fn main() {
     let x: Option<Vec<String>> = None;
@@ -78,3 +78,24 @@ fn issue_12569() {
         0
     };
 }
+
+// Should not warn!
+fn issue_12928() {
+    let x = Some((1, 2));
+    let y = if let Some((a, _)) = x { a } else { 0 };
+    let y = if let Some((a, ..)) = x { a } else { 0 };
+    let x = Some([1, 2]);
+    let y = if let Some([a, _]) = x { a } else { 0 };
+    let y = if let Some([a, ..]) = x { a } else { 0 };
+
+    struct X {
+        a: u8,
+        b: u8,
+    }
+    let x = Some(X { a: 0, b: 0 });
+    let y = if let Some(X { a, .. }) = x { a } else { 0 };
+    struct Y(u8, u8);
+    let x = Some(Y(0, 0));
+    let y = if let Some(Y(a, _)) = x { a } else { 0 };
+    let y = if let Some(Y(a, ..)) = x { a } else { 0 };
+}
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 75ffe09be9d..649f65c89fb 100644
--- a/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs
+++ b/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::manual_unwrap_or_default)]
-#![allow(clippy::unnecessary_literal_unwrap)]
+#![allow(clippy::unnecessary_literal_unwrap, clippy::manual_unwrap_or)]
 
 fn main() {
     let x: Option<Vec<String>> = None;
@@ -111,3 +111,24 @@ fn issue_12569() {
         0
     };
 }
+
+// Should not warn!
+fn issue_12928() {
+    let x = Some((1, 2));
+    let y = if let Some((a, _)) = x { a } else { 0 };
+    let y = if let Some((a, ..)) = x { a } else { 0 };
+    let x = Some([1, 2]);
+    let y = if let Some([a, _]) = x { a } else { 0 };
+    let y = if let Some([a, ..]) = x { a } else { 0 };
+
+    struct X {
+        a: u8,
+        b: u8,
+    }
+    let x = Some(X { a: 0, b: 0 });
+    let y = if let Some(X { a, .. }) = x { a } else { 0 };
+    struct Y(u8, u8);
+    let x = Some(Y(0, 0));
+    let y = if let Some(Y(a, _)) = x { a } else { 0 };
+    let y = if let Some(Y(a, ..)) = x { a } else { 0 };
+}
diff --git a/src/tools/clippy/tests/ui/match_result_ok.fixed b/src/tools/clippy/tests/ui/match_result_ok.fixed
index 76b26f5e438..117e0bc68cc 100644
--- a/src/tools/clippy/tests/ui/match_result_ok.fixed
+++ b/src/tools/clippy/tests/ui/match_result_ok.fixed
@@ -1,6 +1,11 @@
 #![warn(clippy::match_result_ok)]
 #![allow(dead_code)]
-#![allow(clippy::boxed_local, clippy::uninlined_format_args, clippy::manual_unwrap_or_default)]
+#![allow(
+    clippy::boxed_local,
+    clippy::uninlined_format_args,
+    clippy::manual_unwrap_or_default,
+    clippy::manual_unwrap_or
+)]
 
 // Checking `if` cases
 
diff --git a/src/tools/clippy/tests/ui/match_result_ok.rs b/src/tools/clippy/tests/ui/match_result_ok.rs
index d6f2475ba79..f8a5269024d 100644
--- a/src/tools/clippy/tests/ui/match_result_ok.rs
+++ b/src/tools/clippy/tests/ui/match_result_ok.rs
@@ -1,6 +1,11 @@
 #![warn(clippy::match_result_ok)]
 #![allow(dead_code)]
-#![allow(clippy::boxed_local, clippy::uninlined_format_args, clippy::manual_unwrap_or_default)]
+#![allow(
+    clippy::boxed_local,
+    clippy::uninlined_format_args,
+    clippy::manual_unwrap_or_default,
+    clippy::manual_unwrap_or
+)]
 
 // Checking `if` cases
 
diff --git a/src/tools/clippy/tests/ui/match_result_ok.stderr b/src/tools/clippy/tests/ui/match_result_ok.stderr
index 0d42d59dc01..b5b91cbe553 100644
--- a/src/tools/clippy/tests/ui/match_result_ok.stderr
+++ b/src/tools/clippy/tests/ui/match_result_ok.stderr
@@ -1,5 +1,5 @@
 error: matching on `Some` with `ok()` is redundant
-  --> tests/ui/match_result_ok.rs:8:5
+  --> tests/ui/match_result_ok.rs:13:5
    |
 LL |     if let Some(y) = x.parse().ok() { y } else { 0 }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -12,7 +12,7 @@ LL |     if let Ok(y) = x.parse() { y } else { 0 }
    |     ~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: matching on `Some` with `ok()` is redundant
-  --> tests/ui/match_result_ok.rs:18:9
+  --> tests/ui/match_result_ok.rs:23:9
    |
 LL |         if let Some(y) = x   .   parse()   .   ok   ()    {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -23,7 +23,7 @@ LL |         if let Ok(y) = x   .   parse()    {
    |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: matching on `Some` with `ok()` is redundant
-  --> tests/ui/match_result_ok.rs:44:5
+  --> tests/ui/match_result_ok.rs:49:5
    |
 LL |     while let Some(a) = wat.next().ok() {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed
new file mode 100644
index 00000000000..f8fc935f367
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed
@@ -0,0 +1,176 @@
+#![warn(clippy::missing_const_for_fn)]
+#![allow(incomplete_features, clippy::let_and_return, clippy::missing_transmute_annotations)]
+#![feature(const_mut_refs)]
+#![feature(const_trait_impl)]
+
+use std::mem::transmute;
+
+struct Game {
+    guess: i32,
+}
+
+impl Game {
+    // Could be const
+    pub const fn new() -> Self {
+        //~^ ERROR: this could be a `const fn`
+        //~| NOTE: `-D clippy::missing-const-for-fn` implied by `-D warnings`
+        Self { guess: 42 }
+    }
+
+    const fn const_generic_params<'a, T, const N: usize>(&self, b: &'a [T; N]) -> &'a [T; N] {
+        //~^ ERROR: this could be a `const fn`
+        b
+    }
+}
+
+// Could be const
+const fn one() -> i32 {
+    //~^ ERROR: this could be a `const fn`
+    1
+}
+
+// Could also be const
+const fn two() -> i32 {
+    //~^ ERROR: this could be a `const fn`
+    let abc = 2;
+    abc
+}
+
+// Could be const (since Rust 1.39)
+const fn string() -> String {
+    //~^ ERROR: this could be a `const fn`
+    String::new()
+}
+
+// Could be const
+const unsafe fn four() -> i32 {
+    //~^ ERROR: this could be a `const fn`
+    4
+}
+
+// Could also be const
+const fn generic<T>(t: T) -> T {
+    //~^ ERROR: this could be a `const fn`
+    t
+}
+
+fn sub(x: u32) -> usize {
+    unsafe { transmute(&x) }
+}
+
+const fn generic_arr<T: Copy>(t: [T; 1]) -> T {
+    //~^ ERROR: this could be a `const fn`
+    t[0]
+}
+
+mod with_drop {
+    pub struct A;
+    pub struct B;
+    impl Drop for A {
+        fn drop(&mut self) {}
+    }
+
+    impl B {
+        // This can be const, because `a` is passed by reference
+        pub const fn b(self, a: &A) -> B {
+            //~^ ERROR: this could be a `const fn`
+            B
+        }
+    }
+}
+
+#[clippy::msrv = "1.47.0"]
+mod const_fn_stabilized_before_msrv {
+    // This could be const because `u8::is_ascii_digit` is a stable const function in 1.47.
+    const fn const_fn_stabilized_before_msrv(byte: u8) {
+        //~^ ERROR: this could be a `const fn`
+        byte.is_ascii_digit();
+    }
+}
+
+#[clippy::msrv = "1.45"]
+fn msrv_1_45() -> i32 {
+    45
+}
+
+#[clippy::msrv = "1.46"]
+const fn msrv_1_46() -> i32 {
+    //~^ ERROR: this could be a `const fn`
+    46
+}
+
+// Should not be const
+fn main() {}
+
+struct D;
+
+/* FIXME(effects)
+impl const Drop for D {
+    fn drop(&mut self) {
+        todo!();
+    }
+}
+*/
+
+// Lint this, since it can be dropped in const contexts
+// FIXME(effects)
+const fn d(this: D) {}
+//~^ ERROR: this could be a `const fn`
+
+mod msrv {
+    struct Foo(*const u8, &'static u8);
+
+    impl Foo {
+        #[clippy::msrv = "1.58"]
+        const fn deref_ptr_can_be_const(self) -> usize {
+            //~^ ERROR: this could be a `const fn`
+            unsafe { *self.0 as usize }
+        }
+
+        const fn deref_copied_val(self) -> usize {
+            //~^ ERROR: this could be a `const fn`
+            *self.1 as usize
+        }
+    }
+
+    union Bar {
+        val: u8,
+    }
+
+    #[clippy::msrv = "1.56"]
+    const fn union_access_can_be_const() {
+        //~^ ERROR: this could be a `const fn`
+        let bar = Bar { val: 1 };
+        let _ = unsafe { bar.val };
+    }
+}
+
+mod issue12677 {
+    pub struct Wrapper {
+        pub strings: Vec<String>,
+    }
+
+    impl Wrapper {
+        #[must_use]
+        pub const fn new(strings: Vec<String>) -> Self {
+            Self { strings }
+        }
+
+        #[must_use]
+        pub const fn empty() -> Self {
+            Self { strings: Vec::new() }
+        }
+    }
+
+    pub struct Other {
+        pub text: String,
+        pub vec: Vec<String>,
+    }
+
+    impl Other {
+        pub const fn new(text: String) -> Self {
+            let vec = Vec::new();
+            Self { text, vec }
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
index 58e639cc7fd..5e4e2c58e5a 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
@@ -104,15 +104,18 @@ fn main() {}
 
 struct D;
 
+/* FIXME(effects)
 impl const Drop for D {
     fn drop(&mut self) {
         todo!();
     }
 }
+*/
 
 // Lint this, since it can be dropped in const contexts
 // FIXME(effects)
 fn d(this: D) {}
+//~^ ERROR: this could be a `const fn`
 
 mod msrv {
     struct Foo(*const u8, &'static u8);
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
index 1c61c3e8713..8302b074127 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
@@ -10,6 +10,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 |     pub const fn new() -> Self {
+   |         +++++
 
 error: this could be a `const fn`
   --> tests/ui/missing_const_for_fn/could_be_const.rs:20:5
@@ -19,6 +23,11 @@ LL | |
 LL | |         b
 LL | |     }
    | |_____^
+   |
+help: make the function `const`
+   |
+LL |     const fn const_generic_params<'a, T, const N: usize>(&self, b: &'a [T; N]) -> &'a [T; N] {
+   |     +++++
 
 error: this could be a `const fn`
   --> tests/ui/missing_const_for_fn/could_be_const.rs:27:1
@@ -28,6 +37,11 @@ LL | |
 LL | |     1
 LL | | }
    | |_^
+   |
+help: make the function `const`
+   |
+LL | const fn one() -> i32 {
+   | +++++
 
 error: this could be a `const fn`
   --> tests/ui/missing_const_for_fn/could_be_const.rs:33:1
@@ -38,6 +52,11 @@ LL | |     let abc = 2;
 LL | |     abc
 LL | | }
    | |_^
+   |
+help: make the function `const`
+   |
+LL | const fn two() -> i32 {
+   | +++++
 
 error: this could be a `const fn`
   --> tests/ui/missing_const_for_fn/could_be_const.rs:40:1
@@ -47,6 +66,11 @@ LL | |
 LL | |     String::new()
 LL | | }
    | |_^
+   |
+help: make the function `const`
+   |
+LL | const fn string() -> String {
+   | +++++
 
 error: this could be a `const fn`
   --> tests/ui/missing_const_for_fn/could_be_const.rs:46:1
@@ -56,6 +80,11 @@ LL | |
 LL | |     4
 LL | | }
    | |_^
+   |
+help: make the function `const`
+   |
+LL | const unsafe fn four() -> i32 {
+   | +++++
 
 error: this could be a `const fn`
   --> tests/ui/missing_const_for_fn/could_be_const.rs:52:1
@@ -65,6 +94,11 @@ LL | |
 LL | |     t
 LL | | }
    | |_^
+   |
+help: make the function `const`
+   |
+LL | const fn generic<T>(t: T) -> T {
+   | +++++
 
 error: this could be a `const fn`
   --> tests/ui/missing_const_for_fn/could_be_const.rs:61:1
@@ -74,6 +108,11 @@ LL | |
 LL | |     t[0]
 LL | | }
    | |_^
+   |
+help: make the function `const`
+   |
+LL | const fn generic_arr<T: Copy>(t: [T; 1]) -> T {
+   | +++++
 
 error: this could be a `const fn`
   --> tests/ui/missing_const_for_fn/could_be_const.rs:75:9
@@ -83,6 +122,11 @@ LL | |
 LL | |             B
 LL | |         }
    | |_________^
+   |
+help: make the function `const`
+   |
+LL |         pub const fn b(self, a: &A) -> B {
+   |             +++++
 
 error: this could be a `const fn`
   --> tests/ui/missing_const_for_fn/could_be_const.rs:85:5
@@ -92,6 +136,11 @@ LL | |
 LL | |         byte.is_ascii_digit();
 LL | |     }
    | |_____^
+   |
+help: make the function `const`
+   |
+LL |     const fn const_fn_stabilized_before_msrv(byte: u8) {
+   |     +++++
 
 error: this could be a `const fn`
   --> tests/ui/missing_const_for_fn/could_be_const.rs:97:1
@@ -101,27 +150,53 @@ LL | |
 LL | |     46
 LL | | }
    | |_^
+   |
+help: make the function `const`
+   |
+LL | const fn msrv_1_46() -> i32 {
+   | +++++
+
+error: this could be a `const fn`
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:117:1
+   |
+LL | fn d(this: D) {}
+   | ^^^^^^^^^^^^^^^^
+   |
+help: make the function `const`
+   |
+LL | const fn d(this: D) {}
+   | +++++
 
 error: this could be a `const fn`
-  --> tests/ui/missing_const_for_fn/could_be_const.rs:122:9
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:125:9
    |
 LL | /         fn deref_ptr_can_be_const(self) -> usize {
 LL | |
 LL | |             unsafe { *self.0 as usize }
 LL | |         }
    | |_________^
+   |
+help: make the function `const`
+   |
+LL |         const fn deref_ptr_can_be_const(self) -> usize {
+   |         +++++
 
 error: this could be a `const fn`
-  --> tests/ui/missing_const_for_fn/could_be_const.rs:127:9
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:130:9
    |
 LL | /         fn deref_copied_val(self) -> usize {
 LL | |
 LL | |             *self.1 as usize
 LL | |         }
    | |_________^
+   |
+help: make the function `const`
+   |
+LL |         const fn deref_copied_val(self) -> usize {
+   |         +++++
 
 error: this could be a `const fn`
-  --> tests/ui/missing_const_for_fn/could_be_const.rs:138:5
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:141:5
    |
 LL | /     fn union_access_can_be_const() {
 LL | |
@@ -129,31 +204,51 @@ LL | |         let bar = Bar { val: 1 };
 LL | |         let _ = unsafe { bar.val };
 LL | |     }
    | |_____^
+   |
+help: make the function `const`
+   |
+LL |     const fn union_access_can_be_const() {
+   |     +++++
 
 error: this could be a `const fn`
-  --> tests/ui/missing_const_for_fn/could_be_const.rs:152:9
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:155:9
    |
 LL | /         pub fn new(strings: Vec<String>) -> Self {
 LL | |             Self { strings }
 LL | |         }
    | |_________^
+   |
+help: make the function `const`
+   |
+LL |         pub const fn new(strings: Vec<String>) -> Self {
+   |             +++++
 
 error: this could be a `const fn`
-  --> tests/ui/missing_const_for_fn/could_be_const.rs:157:9
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:160:9
    |
 LL | /         pub fn empty() -> Self {
 LL | |             Self { strings: Vec::new() }
 LL | |         }
    | |_________^
+   |
+help: make the function `const`
+   |
+LL |         pub const fn empty() -> Self {
+   |             +++++
 
 error: this could be a `const fn`
-  --> tests/ui/missing_const_for_fn/could_be_const.rs:168:9
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:171:9
    |
 LL | /         pub fn new(text: String) -> Self {
 LL | |             let vec = Vec::new();
 LL | |             Self { text, vec }
 LL | |         }
    | |_________^
+   |
+help: make the function `const`
+   |
+LL |         pub const fn new(text: String) -> Self {
+   |             +++++
 
-error: aborting due to 17 previous errors
+error: aborting due to 18 previous errors
 
diff --git a/src/tools/clippy/tests/ui/modulo_arithmetic_float.rs b/src/tools/clippy/tests/ui/modulo_arithmetic_float.rs
index 37895ea09e7..a5b63bed531 100644
--- a/src/tools/clippy/tests/ui/modulo_arithmetic_float.rs
+++ b/src/tools/clippy/tests/ui/modulo_arithmetic_float.rs
@@ -1,3 +1,5 @@
+#![feature(f128)]
+#![feature(f16)]
 #![warn(clippy::modulo_arithmetic)]
 #![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::modulo_one)]
 
@@ -17,6 +19,19 @@ fn main() {
     //~| NOTE: double check for expected result especially when interoperating with differ
 
     // Lint on floating point numbers
+    let a_f16: f16 = -1.6;
+    let mut b_f16: f16 = 2.1;
+    a_f16 % b_f16;
+    //~^ ERROR: you are using modulo operator on types that might have different signs
+    //~| NOTE: double check for expected result especially when interoperating with differ
+    b_f16 % a_f16;
+    //~^ ERROR: you are using modulo operator on types that might have different signs
+    //~| NOTE: double check for expected result especially when interoperating with differ
+    b_f16 %= a_f16;
+    //~^ ERROR: you are using modulo operator on types that might have different signs
+    //~| NOTE: double check for expected result especially when interoperating with differ
+
+    // Lint on floating point numbers
     let a_f32: f32 = -1.6;
     let mut b_f32: f32 = 2.1;
     a_f32 % b_f32;
@@ -41,6 +56,18 @@ fn main() {
     //~^ ERROR: you are using modulo operator on types that might have different signs
     //~| NOTE: double check for expected result especially when interoperating with differ
 
+    let a_f128: f128 = -1.6;
+    let mut b_f128: f128 = 2.1;
+    a_f128 % b_f128;
+    //~^ ERROR: you are using modulo operator on types that might have different signs
+    //~| NOTE: double check for expected result especially when interoperating with differ
+    b_f128 % a_f128;
+    //~^ ERROR: you are using modulo operator on types that might have different signs
+    //~| NOTE: double check for expected result especially when interoperating with differ
+    b_f128 %= a_f128;
+    //~^ ERROR: you are using modulo operator on types that might have different signs
+    //~| NOTE: double check for expected result especially when interoperating with differ
+
     // No lint when both sides are const and of the same sign
     1.6 % 2.1;
     -1.6 % -2.1;
diff --git a/src/tools/clippy/tests/ui/modulo_arithmetic_float.stderr b/src/tools/clippy/tests/ui/modulo_arithmetic_float.stderr
index fa3a64cfb71..2b4937552bd 100644
--- a/src/tools/clippy/tests/ui/modulo_arithmetic_float.stderr
+++ b/src/tools/clippy/tests/ui/modulo_arithmetic_float.stderr
@@ -1,5 +1,5 @@
 error: you are using modulo operator on constants with different signs: `-1.600 % 2.100`
-  --> tests/ui/modulo_arithmetic_float.rs:6:5
+  --> tests/ui/modulo_arithmetic_float.rs:8:5
    |
 LL |     -1.6 % 2.1;
    |     ^^^^^^^^^^
@@ -9,7 +9,7 @@ LL |     -1.6 % 2.1;
    = help: to override `-D warnings` add `#[allow(clippy::modulo_arithmetic)]`
 
 error: you are using modulo operator on constants with different signs: `1.600 % -2.100`
-  --> tests/ui/modulo_arithmetic_float.rs:9:5
+  --> tests/ui/modulo_arithmetic_float.rs:11:5
    |
 LL |     1.6 % -2.1;
    |     ^^^^^^^^^^
@@ -17,7 +17,7 @@ LL |     1.6 % -2.1;
    = note: double check for expected result especially when interoperating with different languages
 
 error: you are using modulo operator on constants with different signs: `-1.200 % 3.400`
-  --> tests/ui/modulo_arithmetic_float.rs:12:5
+  --> tests/ui/modulo_arithmetic_float.rs:14:5
    |
 LL |     (1.1 - 2.3) % (1.1 + 2.3);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -25,7 +25,7 @@ LL |     (1.1 - 2.3) % (1.1 + 2.3);
    = note: double check for expected result especially when interoperating with different languages
 
 error: you are using modulo operator on constants with different signs: `3.400 % -1.200`
-  --> tests/ui/modulo_arithmetic_float.rs:15:5
+  --> tests/ui/modulo_arithmetic_float.rs:17:5
    |
 LL |     (1.1 + 2.3) % (1.1 - 2.3);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -33,7 +33,31 @@ LL |     (1.1 + 2.3) % (1.1 - 2.3);
    = note: double check for expected result especially when interoperating with different languages
 
 error: you are using modulo operator on types that might have different signs
-  --> tests/ui/modulo_arithmetic_float.rs:22:5
+  --> tests/ui/modulo_arithmetic_float.rs:24:5
+   |
+LL |     a_f16 % b_f16;
+   |     ^^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+
+error: you are using modulo operator on types that might have different signs
+  --> tests/ui/modulo_arithmetic_float.rs:27:5
+   |
+LL |     b_f16 % a_f16;
+   |     ^^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+
+error: you are using modulo operator on types that might have different signs
+  --> tests/ui/modulo_arithmetic_float.rs:30:5
+   |
+LL |     b_f16 %= a_f16;
+   |     ^^^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+
+error: you are using modulo operator on types that might have different signs
+  --> tests/ui/modulo_arithmetic_float.rs:37:5
    |
 LL |     a_f32 % b_f32;
    |     ^^^^^^^^^^^^^
@@ -41,7 +65,7 @@ LL |     a_f32 % b_f32;
    = note: double check for expected result especially when interoperating with different languages
 
 error: you are using modulo operator on types that might have different signs
-  --> tests/ui/modulo_arithmetic_float.rs:25:5
+  --> tests/ui/modulo_arithmetic_float.rs:40:5
    |
 LL |     b_f32 % a_f32;
    |     ^^^^^^^^^^^^^
@@ -49,7 +73,7 @@ LL |     b_f32 % a_f32;
    = note: double check for expected result especially when interoperating with different languages
 
 error: you are using modulo operator on types that might have different signs
-  --> tests/ui/modulo_arithmetic_float.rs:28:5
+  --> tests/ui/modulo_arithmetic_float.rs:43:5
    |
 LL |     b_f32 %= a_f32;
    |     ^^^^^^^^^^^^^^
@@ -57,7 +81,7 @@ LL |     b_f32 %= a_f32;
    = note: double check for expected result especially when interoperating with different languages
 
 error: you are using modulo operator on types that might have different signs
-  --> tests/ui/modulo_arithmetic_float.rs:34:5
+  --> tests/ui/modulo_arithmetic_float.rs:49:5
    |
 LL |     a_f64 % b_f64;
    |     ^^^^^^^^^^^^^
@@ -65,7 +89,7 @@ LL |     a_f64 % b_f64;
    = note: double check for expected result especially when interoperating with different languages
 
 error: you are using modulo operator on types that might have different signs
-  --> tests/ui/modulo_arithmetic_float.rs:37:5
+  --> tests/ui/modulo_arithmetic_float.rs:52:5
    |
 LL |     b_f64 % a_f64;
    |     ^^^^^^^^^^^^^
@@ -73,12 +97,36 @@ LL |     b_f64 % a_f64;
    = note: double check for expected result especially when interoperating with different languages
 
 error: you are using modulo operator on types that might have different signs
-  --> tests/ui/modulo_arithmetic_float.rs:40:5
+  --> tests/ui/modulo_arithmetic_float.rs:55:5
    |
 LL |     b_f64 %= a_f64;
    |     ^^^^^^^^^^^^^^
    |
    = note: double check for expected result especially when interoperating with different languages
 
-error: aborting due to 10 previous errors
+error: you are using modulo operator on types that might have different signs
+  --> tests/ui/modulo_arithmetic_float.rs:61:5
+   |
+LL |     a_f128 % b_f128;
+   |     ^^^^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+
+error: you are using modulo operator on types that might have different signs
+  --> tests/ui/modulo_arithmetic_float.rs:64:5
+   |
+LL |     b_f128 % a_f128;
+   |     ^^^^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+
+error: you are using modulo operator on types that might have different signs
+  --> tests/ui/modulo_arithmetic_float.rs:67:5
+   |
+LL |     b_f128 %= a_f128;
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = note: double check for expected result especially when interoperating with different languages
+
+error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_borrow.fixed b/src/tools/clippy/tests/ui/needless_borrow.fixed
index 5121077b4ca..cabdc22bda8 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.fixed
+++ b/src/tools/clippy/tests/ui/needless_borrow.fixed
@@ -1,4 +1,3 @@
-#![feature(lint_reasons)]
 #![allow(
     unused,
     non_local_definitions,
diff --git a/src/tools/clippy/tests/ui/needless_borrow.rs b/src/tools/clippy/tests/ui/needless_borrow.rs
index e3a5cb280ba..50062589645 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.rs
+++ b/src/tools/clippy/tests/ui/needless_borrow.rs
@@ -1,4 +1,3 @@
-#![feature(lint_reasons)]
 #![allow(
     unused,
     non_local_definitions,
diff --git a/src/tools/clippy/tests/ui/needless_borrow.stderr b/src/tools/clippy/tests/ui/needless_borrow.stderr
index 4b2b17e7e57..bf0e265c250 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.stderr
+++ b/src/tools/clippy/tests/ui/needless_borrow.stderr
@@ -1,5 +1,5 @@
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:16:15
+  --> tests/ui/needless_borrow.rs:15:15
    |
 LL |     let _ = x(&&a); // warn
    |               ^^^ help: change this to: `&a`
@@ -8,163 +8,163 @@ LL |     let _ = x(&&a); // warn
    = help: to override `-D warnings` add `#[allow(clippy::needless_borrow)]`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:20:13
+  --> tests/ui/needless_borrow.rs:19:13
    |
 LL |     mut_ref(&mut &mut b); // warn
    |             ^^^^^^^^^^^ help: change this to: `&mut b`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:32:13
+  --> tests/ui/needless_borrow.rs:31:13
    |
 LL |             &&a
    |             ^^^ help: change this to: `&a`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:34:15
+  --> tests/ui/needless_borrow.rs:33:15
    |
 LL |         46 => &&a,
    |               ^^^ help: change this to: `&a`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:40:27
+  --> tests/ui/needless_borrow.rs:39:27
    |
 LL |                     break &ref_a;
    |                           ^^^^^^ help: change this to: `ref_a`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:47:15
+  --> tests/ui/needless_borrow.rs:46:15
    |
 LL |     let _ = x(&&&a);
    |               ^^^^ help: change this to: `&a`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:48:15
+  --> tests/ui/needless_borrow.rs:47:15
    |
 LL |     let _ = x(&mut &&a);
    |               ^^^^^^^^ help: change this to: `&a`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:49:15
+  --> tests/ui/needless_borrow.rs:48:15
    |
 LL |     let _ = x(&&&mut b);
    |               ^^^^^^^^ help: change this to: `&mut b`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:50:15
+  --> tests/ui/needless_borrow.rs:49:15
    |
 LL |     let _ = x(&&ref_a);
    |               ^^^^^^^ help: change this to: `ref_a`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:53:11
+  --> tests/ui/needless_borrow.rs:52:11
    |
 LL |         x(&b);
    |           ^^ help: change this to: `b`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:60:13
+  --> tests/ui/needless_borrow.rs:59:13
    |
 LL |     mut_ref(&mut x);
    |             ^^^^^^ help: change this to: `x`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:61:13
+  --> tests/ui/needless_borrow.rs:60:13
    |
 LL |     mut_ref(&mut &mut x);
    |             ^^^^^^^^^^^ help: change this to: `x`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:62:23
+  --> tests/ui/needless_borrow.rs:61:23
    |
 LL |     let y: &mut i32 = &mut x;
    |                       ^^^^^^ help: change this to: `x`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:63:23
+  --> tests/ui/needless_borrow.rs:62:23
    |
 LL |     let y: &mut i32 = &mut &mut x;
    |                       ^^^^^^^^^^^ help: change this to: `x`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:72:14
+  --> tests/ui/needless_borrow.rs:71:14
    |
 LL |         0 => &mut x,
    |              ^^^^^^ help: change this to: `x`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:78:14
+  --> tests/ui/needless_borrow.rs:77:14
    |
 LL |         0 => &mut x,
    |              ^^^^^^ help: change this to: `x`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> tests/ui/needless_borrow.rs:90:13
+  --> tests/ui/needless_borrow.rs:89:13
    |
 LL |     let _ = (&x).0;
    |             ^^^^ help: change this to: `x`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> tests/ui/needless_borrow.rs:92:22
+  --> tests/ui/needless_borrow.rs:91:22
    |
 LL |     let _ = unsafe { (&*x).0 };
    |                      ^^^^^ help: change this to: `(*x)`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:102:5
+  --> tests/ui/needless_borrow.rs:101:5
    |
 LL |     (&&()).foo();
    |     ^^^^^^ help: change this to: `(&())`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:111:5
+  --> tests/ui/needless_borrow.rs:110:5
    |
 LL |     (&&5).foo();
    |     ^^^^^ help: change this to: `(&5)`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:137:23
+  --> tests/ui/needless_borrow.rs:136:23
    |
 LL |     let x: (&str,) = (&"",);
    |                       ^^^ help: change this to: `""`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> tests/ui/needless_borrow.rs:179:13
+  --> tests/ui/needless_borrow.rs:178:13
    |
 LL |             (&self.f)()
    |             ^^^^^^^^^ help: change this to: `(self.f)`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> tests/ui/needless_borrow.rs:188:13
+  --> tests/ui/needless_borrow.rs:187:13
    |
 LL |             (&mut self.f)()
    |             ^^^^^^^^^^^^^ help: change this to: `(self.f)`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> tests/ui/needless_borrow.rs:225:22
+  --> tests/ui/needless_borrow.rs:224:22
    |
 LL |         let _ = &mut (&mut { x.u }).x;
    |                      ^^^^^^^^^^^^^^ help: change this to: `{ x.u }`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> tests/ui/needless_borrow.rs:232:22
+  --> tests/ui/needless_borrow.rs:231:22
    |
 LL |         let _ = &mut (&mut { x.u }).x;
    |                      ^^^^^^^^^^^^^^ help: change this to: `{ x.u }`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> tests/ui/needless_borrow.rs:236:22
+  --> tests/ui/needless_borrow.rs:235:22
    |
 LL |         let _ = &mut (&mut x.u).x;
    |                      ^^^^^^^^^^ help: change this to: `x.u`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> tests/ui/needless_borrow.rs:237:22
+  --> tests/ui/needless_borrow.rs:236:22
    |
 LL |         let _ = &mut (&mut { x.u }).x;
    |                      ^^^^^^^^^^^^^^ help: change this to: `{ x.u }`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:258:23
+  --> tests/ui/needless_borrow.rs:257:23
    |
 LL |     option.unwrap_or((&x.0,));
    |                       ^^^^ help: change this to: `x.0`
diff --git a/src/tools/clippy/tests/ui/needless_collect_indirect.stderr b/src/tools/clippy/tests/ui/needless_collect_indirect.stderr
index 0cce718a1ac..f25c0293754 100644
--- a/src/tools/clippy/tests/ui/needless_collect_indirect.stderr
+++ b/src/tools/clippy/tests/ui/needless_collect_indirect.stderr
@@ -212,7 +212,7 @@ help: check if the original Iterator contains an element instead of collecting t
    |
 LL ~             
 LL |
- ...
+...
 LL |                 // Do lint
 LL ~                 vec.iter().map(|k| k * k).any(|x| x == n);
    |
diff --git a/src/tools/clippy/tests/ui/needless_late_init.stderr b/src/tools/clippy/tests/ui/needless_late_init.stderr
index ce64861fa40..de048091cfb 100644
--- a/src/tools/clippy/tests/ui/needless_late_init.stderr
+++ b/src/tools/clippy/tests/ui/needless_late_init.stderr
@@ -215,7 +215,7 @@ help: move the declaration `x` here
    |
 LL ~     
 LL |     // types that should be considered insignificant
- ...
+...
 LL |     let y = Box::new(4);
 LL ~     let x = SignificantDrop;
    |
diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs
index 3f5f55f4002..eee62122fdf 100644
--- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs
+++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs
@@ -5,7 +5,6 @@
     clippy::ptr_arg
 )]
 #![warn(clippy::needless_pass_by_ref_mut)]
-#![feature(lint_reasons)]
 //@no-rustfix
 use std::ptr::NonNull;
 
diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr
index 21ca393dcb6..51e3ba37ded 100644
--- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr
+++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr
@@ -1,5 +1,5 @@
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:12:11
+  --> tests/ui/needless_pass_by_ref_mut.rs:11:11
    |
 LL | fn foo(s: &mut Vec<u32>, b: &u32, x: &mut u32) {
    |           ^^^^^^^^^^^^^ help: consider changing to: `&Vec<u32>`
@@ -8,79 +8,79 @@ LL | fn foo(s: &mut Vec<u32>, b: &u32, x: &mut u32) {
    = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:37:12
+  --> tests/ui/needless_pass_by_ref_mut.rs:36:12
    |
 LL | fn foo6(s: &mut Vec<u32>) {
    |            ^^^^^^^^^^^^^ help: consider changing to: `&Vec<u32>`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:47:12
+  --> tests/ui/needless_pass_by_ref_mut.rs:46:12
    |
 LL |     fn bar(&mut self) {}
    |            ^^^^^^^^^ help: consider changing to: `&self`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:50:29
+  --> tests/ui/needless_pass_by_ref_mut.rs:49:29
    |
 LL |     fn mushroom(&self, vec: &mut Vec<i32>) -> usize {
    |                             ^^^^^^^^^^^^^ help: consider changing to: `&Vec<i32>`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:127:16
+  --> tests/ui/needless_pass_by_ref_mut.rs:126:16
    |
 LL | async fn a1(x: &mut i32) {
    |                ^^^^^^^^ help: consider changing to: `&i32`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:131:16
+  --> tests/ui/needless_pass_by_ref_mut.rs:130:16
    |
 LL | async fn a2(x: &mut i32, y: String) {
    |                ^^^^^^^^ help: consider changing to: `&i32`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:135:16
+  --> tests/ui/needless_pass_by_ref_mut.rs:134:16
    |
 LL | async fn a3(x: &mut i32, y: String, z: String) {
    |                ^^^^^^^^ help: consider changing to: `&i32`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:139:16
+  --> tests/ui/needless_pass_by_ref_mut.rs:138:16
    |
 LL | async fn a4(x: &mut i32, y: i32) {
    |                ^^^^^^^^ help: consider changing to: `&i32`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:143:24
+  --> tests/ui/needless_pass_by_ref_mut.rs:142:24
    |
 LL | async fn a5(x: i32, y: &mut i32) {
    |                        ^^^^^^^^ help: consider changing to: `&i32`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:147:24
+  --> tests/ui/needless_pass_by_ref_mut.rs:146:24
    |
 LL | async fn a6(x: i32, y: &mut i32) {
    |                        ^^^^^^^^ help: consider changing to: `&i32`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:151:32
+  --> tests/ui/needless_pass_by_ref_mut.rs:150:32
    |
 LL | async fn a7(x: i32, y: i32, z: &mut i32) {
    |                                ^^^^^^^^ help: consider changing to: `&i32`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:155:24
+  --> tests/ui/needless_pass_by_ref_mut.rs:154:24
    |
 LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) {
    |                        ^^^^^^^^ help: consider changing to: `&i32`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:155:45
+  --> tests/ui/needless_pass_by_ref_mut.rs:154:45
    |
 LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) {
    |                                             ^^^^^^^^ help: consider changing to: `&i32`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:189:16
+  --> tests/ui/needless_pass_by_ref_mut.rs:188:16
    |
 LL | fn cfg_warn(s: &mut u32) {}
    |                ^^^^^^^^ help: consider changing to: `&u32`
@@ -88,7 +88,7 @@ LL | fn cfg_warn(s: &mut u32) {}
    = note: this is cfg-gated and may require further changes
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:195:20
+  --> tests/ui/needless_pass_by_ref_mut.rs:194:20
    |
 LL |     fn cfg_warn(s: &mut u32) {}
    |                    ^^^^^^^^ help: consider changing to: `&u32`
@@ -96,19 +96,19 @@ LL |     fn cfg_warn(s: &mut u32) {}
    = note: this is cfg-gated and may require further changes
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:209:39
+  --> tests/ui/needless_pass_by_ref_mut.rs:208:39
    |
 LL | async fn inner_async2(x: &mut i32, y: &mut u32) {
    |                                       ^^^^^^^^ help: consider changing to: `&u32`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:217:26
+  --> tests/ui/needless_pass_by_ref_mut.rs:216:26
    |
 LL | async fn inner_async3(x: &mut i32, y: &mut u32) {
    |                          ^^^^^^^^ help: consider changing to: `&i32`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:236:34
+  --> tests/ui/needless_pass_by_ref_mut.rs:235:34
    |
 LL | pub async fn call_in_closure1(n: &mut str) {
    |                                  ^^^^^^^^ help: consider changing to: `&str`
@@ -116,7 +116,7 @@ LL | pub async fn call_in_closure1(n: &mut str) {
    = warning: changing this function will impact semver compatibility
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:255:20
+  --> tests/ui/needless_pass_by_ref_mut.rs:254:20
    |
 LL | pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize {
    |                    ^^^^^^^^^^ help: consider changing to: `&usize`
@@ -124,7 +124,7 @@ LL | pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize {
    = warning: changing this function will impact semver compatibility
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:266:26
+  --> tests/ui/needless_pass_by_ref_mut.rs:265:26
    |
 LL | pub async fn closure4(n: &mut usize) {
    |                          ^^^^^^^^^^ help: consider changing to: `&usize`
@@ -132,85 +132,85 @@ LL | pub async fn closure4(n: &mut usize) {
    = warning: changing this function will impact semver compatibility
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:315:12
+  --> tests/ui/needless_pass_by_ref_mut.rs:314:12
    |
 LL |     fn bar(&mut self) {}
    |            ^^^^^^^^^ help: consider changing to: `&self`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:317:18
+  --> tests/ui/needless_pass_by_ref_mut.rs:316:18
    |
 LL |     async fn foo(&mut self, u: &mut i32, v: &mut u32) {
    |                  ^^^^^^^^^ help: consider changing to: `&self`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:317:45
+  --> tests/ui/needless_pass_by_ref_mut.rs:316:45
    |
 LL |     async fn foo(&mut self, u: &mut i32, v: &mut u32) {
    |                                             ^^^^^^^^ help: consider changing to: `&u32`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:325:46
+  --> tests/ui/needless_pass_by_ref_mut.rs:324:46
    |
 LL |     async fn foo2(&mut self, u: &mut i32, v: &mut u32) {
    |                                              ^^^^^^^^ help: consider changing to: `&u32`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:341:18
+  --> tests/ui/needless_pass_by_ref_mut.rs:340:18
    |
 LL | fn _empty_tup(x: &mut (())) {}
    |                  ^^^^^^^^^ help: consider changing to: `&()`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:342:19
+  --> tests/ui/needless_pass_by_ref_mut.rs:341:19
    |
 LL | fn _single_tup(x: &mut ((i32,))) {}
    |                   ^^^^^^^^^^^^^ help: consider changing to: `&(i32,)`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:343:18
+  --> tests/ui/needless_pass_by_ref_mut.rs:342:18
    |
 LL | fn _multi_tup(x: &mut ((i32, u32))) {}
    |                  ^^^^^^^^^^^^^^^^^ help: consider changing to: `&(i32, u32)`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:344:11
+  --> tests/ui/needless_pass_by_ref_mut.rs:343:11
    |
 LL | fn _fn(x: &mut (fn())) {}
    |           ^^^^^^^^^^^ help: consider changing to: `&fn()`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:346:23
+  --> tests/ui/needless_pass_by_ref_mut.rs:345:23
    |
 LL | fn _extern_rust_fn(x: &mut extern "Rust" fn()) {}
    |                       ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "Rust" fn()`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:347:20
+  --> tests/ui/needless_pass_by_ref_mut.rs:346:20
    |
 LL | fn _extern_c_fn(x: &mut extern "C" fn()) {}
    |                    ^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "C" fn()`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:348:18
+  --> tests/ui/needless_pass_by_ref_mut.rs:347:18
    |
 LL | fn _unsafe_fn(x: &mut unsafe fn()) {}
    |                  ^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe fn()`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:349:25
+  --> tests/ui/needless_pass_by_ref_mut.rs:348:25
    |
 LL | fn _unsafe_extern_fn(x: &mut unsafe extern "C" fn()) {}
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn()`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:350:20
+  --> tests/ui/needless_pass_by_ref_mut.rs:349:20
    |
 LL | fn _fn_with_arg(x: &mut unsafe extern "C" fn(i32)) {}
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn(i32)`
 
 error: this argument is a mutable reference, but not used mutably
-  --> tests/ui/needless_pass_by_ref_mut.rs:351:20
+  --> tests/ui/needless_pass_by_ref_mut.rs:350:20
    |
 LL | fn _fn_with_ret(x: &mut unsafe extern "C" fn() -> (i32)) {}
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn() -> (i32)`
diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed
index a9271cb399d..853f685f04c 100644
--- a/src/tools/clippy/tests/ui/needless_return.fixed
+++ b/src/tools/clippy/tests/ui/needless_return.fixed
@@ -1,4 +1,3 @@
-#![feature(lint_reasons)]
 #![feature(yeet_expr)]
 #![allow(unused)]
 #![allow(
diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs
index dc888bf667f..e9c1e0e8ae8 100644
--- a/src/tools/clippy/tests/ui/needless_return.rs
+++ b/src/tools/clippy/tests/ui/needless_return.rs
@@ -1,4 +1,3 @@
-#![feature(lint_reasons)]
 #![feature(yeet_expr)]
 #![allow(unused)]
 #![allow(
diff --git a/src/tools/clippy/tests/ui/needless_return.stderr b/src/tools/clippy/tests/ui/needless_return.stderr
index bf5a89d8b75..6c891fe7ad3 100644
--- a/src/tools/clippy/tests/ui/needless_return.stderr
+++ b/src/tools/clippy/tests/ui/needless_return.stderr
@@ -1,5 +1,5 @@
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:26:5
+  --> tests/ui/needless_return.rs:25:5
    |
 LL |     return true;
    |     ^^^^^^^^^^^
@@ -13,7 +13,7 @@ LL +     true
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:30:5
+  --> tests/ui/needless_return.rs:29:5
    |
 LL |     return true;
    |     ^^^^^^^^^^^
@@ -25,7 +25,7 @@ LL +     true
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:35:5
+  --> tests/ui/needless_return.rs:34:5
    |
 LL |     return true;;;
    |     ^^^^^^^^^^^
@@ -37,7 +37,7 @@ LL +     true
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:40:5
+  --> tests/ui/needless_return.rs:39:5
    |
 LL |     return true;; ; ;
    |     ^^^^^^^^^^^
@@ -49,7 +49,7 @@ LL +     true
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:45:9
+  --> tests/ui/needless_return.rs:44:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
@@ -61,7 +61,7 @@ LL +         true
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:47:9
+  --> tests/ui/needless_return.rs:46:9
    |
 LL |         return false;
    |         ^^^^^^^^^^^^
@@ -73,7 +73,7 @@ LL +         false
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:53:17
+  --> tests/ui/needless_return.rs:52:17
    |
 LL |         true => return false,
    |                 ^^^^^^^^^^^^
@@ -84,7 +84,7 @@ LL |         true => false,
    |                 ~~~~~
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:55:13
+  --> tests/ui/needless_return.rs:54:13
    |
 LL |             return true;
    |             ^^^^^^^^^^^
@@ -96,7 +96,7 @@ LL +             true
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:62:9
+  --> tests/ui/needless_return.rs:61:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
@@ -108,7 +108,7 @@ LL +         true
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:64:16
+  --> tests/ui/needless_return.rs:63:16
    |
 LL |     let _ = || return true;
    |                ^^^^^^^^^^^
@@ -119,7 +119,7 @@ LL |     let _ = || true;
    |                ~~~~
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:68:5
+  --> tests/ui/needless_return.rs:67:5
    |
 LL |     return the_answer!();
    |     ^^^^^^^^^^^^^^^^^^^^
@@ -131,7 +131,7 @@ LL +     the_answer!()
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:71:21
+  --> tests/ui/needless_return.rs:70:21
    |
 LL |   fn test_void_fun() {
    |  _____________________^
@@ -146,7 +146,7 @@ LL + fn test_void_fun() {
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:76:11
+  --> tests/ui/needless_return.rs:75:11
    |
 LL |       if b {
    |  ___________^
@@ -161,7 +161,7 @@ LL +     if b {
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:78:13
+  --> tests/ui/needless_return.rs:77:13
    |
 LL |       } else {
    |  _____________^
@@ -176,7 +176,7 @@ LL +     } else {
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:86:14
+  --> tests/ui/needless_return.rs:85:14
    |
 LL |         _ => return,
    |              ^^^^^^
@@ -187,7 +187,7 @@ LL |         _ => (),
    |              ~~
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:94:24
+  --> tests/ui/needless_return.rs:93:24
    |
 LL |               let _ = 42;
    |  ________________________^
@@ -202,7 +202,7 @@ LL +             let _ = 42;
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:97:14
+  --> tests/ui/needless_return.rs:96:14
    |
 LL |         _ => return,
    |              ^^^^^^
@@ -213,7 +213,7 @@ LL |         _ => (),
    |              ~~
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:110:9
+  --> tests/ui/needless_return.rs:109:9
    |
 LL |         return String::from("test");
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -225,7 +225,7 @@ LL +         String::from("test")
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:112:9
+  --> tests/ui/needless_return.rs:111:9
    |
 LL |         return String::new();
    |         ^^^^^^^^^^^^^^^^^^^^
@@ -237,7 +237,7 @@ LL +         String::new()
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:134:32
+  --> tests/ui/needless_return.rs:133:32
    |
 LL |         bar.unwrap_or_else(|_| return)
    |                                ^^^^^^
@@ -248,7 +248,7 @@ LL |         bar.unwrap_or_else(|_| {})
    |                                ~~
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:138:21
+  --> tests/ui/needless_return.rs:137:21
    |
 LL |           let _ = || {
    |  _____________________^
@@ -263,7 +263,7 @@ LL +         let _ = || {
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:141:20
+  --> tests/ui/needless_return.rs:140:20
    |
 LL |         let _ = || return;
    |                    ^^^^^^
@@ -274,7 +274,7 @@ LL |         let _ = || {};
    |                    ~~
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:147:32
+  --> tests/ui/needless_return.rs:146:32
    |
 LL |         res.unwrap_or_else(|_| return Foo)
    |                                ^^^^^^^^^^
@@ -285,7 +285,7 @@ LL |         res.unwrap_or_else(|_| Foo)
    |                                ~~~
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:156:5
+  --> tests/ui/needless_return.rs:155:5
    |
 LL |     return true;
    |     ^^^^^^^^^^^
@@ -297,7 +297,7 @@ LL +     true
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:160:5
+  --> tests/ui/needless_return.rs:159:5
    |
 LL |     return true;
    |     ^^^^^^^^^^^
@@ -309,7 +309,7 @@ LL +     true
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:165:9
+  --> tests/ui/needless_return.rs:164:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
@@ -321,7 +321,7 @@ LL +         true
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:167:9
+  --> tests/ui/needless_return.rs:166:9
    |
 LL |         return false;
    |         ^^^^^^^^^^^^
@@ -333,7 +333,7 @@ LL +         false
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:173:17
+  --> tests/ui/needless_return.rs:172:17
    |
 LL |         true => return false,
    |                 ^^^^^^^^^^^^
@@ -344,7 +344,7 @@ LL |         true => false,
    |                 ~~~~~
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:175:13
+  --> tests/ui/needless_return.rs:174:13
    |
 LL |             return true;
    |             ^^^^^^^^^^^
@@ -356,7 +356,7 @@ LL +             true
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:182:9
+  --> tests/ui/needless_return.rs:181:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
@@ -368,7 +368,7 @@ LL +         true
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:184:16
+  --> tests/ui/needless_return.rs:183:16
    |
 LL |     let _ = || return true;
    |                ^^^^^^^^^^^
@@ -379,7 +379,7 @@ LL |     let _ = || true;
    |                ~~~~
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:188:5
+  --> tests/ui/needless_return.rs:187:5
    |
 LL |     return the_answer!();
    |     ^^^^^^^^^^^^^^^^^^^^
@@ -391,7 +391,7 @@ LL +     the_answer!()
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:191:33
+  --> tests/ui/needless_return.rs:190:33
    |
 LL |   async fn async_test_void_fun() {
    |  _________________________________^
@@ -406,7 +406,7 @@ LL + async fn async_test_void_fun() {
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:196:11
+  --> tests/ui/needless_return.rs:195:11
    |
 LL |       if b {
    |  ___________^
@@ -421,7 +421,7 @@ LL +     if b {
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:198:13
+  --> tests/ui/needless_return.rs:197:13
    |
 LL |       } else {
    |  _____________^
@@ -436,7 +436,7 @@ LL +     } else {
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:206:14
+  --> tests/ui/needless_return.rs:205:14
    |
 LL |         _ => return,
    |              ^^^^^^
@@ -447,7 +447,7 @@ LL |         _ => (),
    |              ~~
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:219:9
+  --> tests/ui/needless_return.rs:218:9
    |
 LL |         return String::from("test");
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -459,7 +459,7 @@ LL +         String::from("test")
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:221:9
+  --> tests/ui/needless_return.rs:220:9
    |
 LL |         return String::new();
    |         ^^^^^^^^^^^^^^^^^^^^
@@ -471,7 +471,7 @@ LL +         String::new()
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:237:5
+  --> tests/ui/needless_return.rs:236:5
    |
 LL |     return format!("Hello {}", "world!");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -483,7 +483,7 @@ LL +     format!("Hello {}", "world!")
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:249:9
+  --> tests/ui/needless_return.rs:248:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
@@ -497,7 +497,7 @@ LL ~     }
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:251:9
+  --> tests/ui/needless_return.rs:250:9
    |
 LL |         return false;
    |         ^^^^^^^^^^^^
@@ -509,7 +509,7 @@ LL ~     }
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:258:13
+  --> tests/ui/needless_return.rs:257:13
    |
 LL |             return 10;
    |             ^^^^^^^^^
@@ -518,13 +518,13 @@ help: remove `return`
    |
 LL ~             10
 LL |         },
- ...
+...
 LL |         },
 LL ~     }
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:261:13
+  --> tests/ui/needless_return.rs:260:13
    |
 LL |             return 100;
    |             ^^^^^^^^^^
@@ -537,7 +537,7 @@ LL ~     }
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:269:9
+  --> tests/ui/needless_return.rs:268:9
    |
 LL |         return 0;
    |         ^^^^^^^^
@@ -549,7 +549,7 @@ LL ~     }
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:276:13
+  --> tests/ui/needless_return.rs:275:13
    |
 LL |             return *(x as *const isize);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -564,7 +564,7 @@ LL ~     }
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:278:13
+  --> tests/ui/needless_return.rs:277:13
    |
 LL |             return !*(x as *const isize);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -577,7 +577,7 @@ LL ~     }
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:285:20
+  --> tests/ui/needless_return.rs:284:20
    |
 LL |           let _ = 42;
    |  ____________________^
@@ -594,7 +594,7 @@ LL +         let _ = 42;
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:292:20
+  --> tests/ui/needless_return.rs:291:20
    |
 LL |         let _ = 42; return;
    |                    ^^^^^^^
@@ -606,7 +606,7 @@ LL +         let _ = 42;
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:304:9
+  --> tests/ui/needless_return.rs:303:9
    |
 LL |         return Ok(format!("ok!"));
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -618,7 +618,7 @@ LL +         Ok(format!("ok!"))
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:306:9
+  --> tests/ui/needless_return.rs:305:9
    |
 LL |         return Err(format!("err!"));
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -630,7 +630,7 @@ LL +         Err(format!("err!"))
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:312:9
+  --> tests/ui/needless_return.rs:311:9
    |
 LL |         return if true { 1 } else { 2 };
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -642,7 +642,7 @@ LL +         if true { 1 } else { 2 }
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:316:9
+  --> tests/ui/needless_return.rs:315:9
    |
 LL |         return if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 };
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -654,7 +654,7 @@ LL +         (if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:337:5
+  --> tests/ui/needless_return.rs:336:5
    |
 LL |     return { "a".to_string() } + "b" + { "c" };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/nonminimal_bool.rs b/src/tools/clippy/tests/ui/nonminimal_bool.rs
index 38157116e91..d117e8bf9c7 100644
--- a/src/tools/clippy/tests/ui/nonminimal_bool.rs
+++ b/src/tools/clippy/tests/ui/nonminimal_bool.rs
@@ -1,6 +1,4 @@
 //@no-rustfix: overlapping suggestions
-
-#![feature(lint_reasons)]
 #![allow(
     unused,
     clippy::diverging_sub_expression,
diff --git a/src/tools/clippy/tests/ui/nonminimal_bool.stderr b/src/tools/clippy/tests/ui/nonminimal_bool.stderr
index b6af06d845a..eafffdaf8a6 100644
--- a/src/tools/clippy/tests/ui/nonminimal_bool.stderr
+++ b/src/tools/clippy/tests/ui/nonminimal_bool.stderr
@@ -1,5 +1,5 @@
 error: this boolean expression can be simplified
-  --> tests/ui/nonminimal_bool.rs:19:13
+  --> tests/ui/nonminimal_bool.rs:17:13
    |
 LL |     let _ = !true;
    |             ^^^^^ help: try: `false`
@@ -8,43 +8,43 @@ LL |     let _ = !true;
    = help: to override `-D warnings` add `#[allow(clippy::nonminimal_bool)]`
 
 error: this boolean expression can be simplified
-  --> tests/ui/nonminimal_bool.rs:22:13
+  --> tests/ui/nonminimal_bool.rs:20:13
    |
 LL |     let _ = !false;
    |             ^^^^^^ help: try: `true`
 
 error: this boolean expression can be simplified
-  --> tests/ui/nonminimal_bool.rs:24:13
+  --> tests/ui/nonminimal_bool.rs:22:13
    |
 LL |     let _ = !!a;
    |             ^^^ help: try: `a`
 
 error: this boolean expression can be simplified
-  --> tests/ui/nonminimal_bool.rs:26:13
+  --> tests/ui/nonminimal_bool.rs:24:13
    |
 LL |     let _ = false || a;
    |             ^^^^^^^^^^ help: try: `a`
 
 error: this boolean expression can be simplified
-  --> tests/ui/nonminimal_bool.rs:31:13
+  --> tests/ui/nonminimal_bool.rs:29:13
    |
 LL |     let _ = !(!a && b);
    |             ^^^^^^^^^^ help: try: `a || !b`
 
 error: this boolean expression can be simplified
-  --> tests/ui/nonminimal_bool.rs:33:13
+  --> tests/ui/nonminimal_bool.rs:31:13
    |
 LL |     let _ = !(!a || b);
    |             ^^^^^^^^^^ help: try: `a && !b`
 
 error: this boolean expression can be simplified
-  --> tests/ui/nonminimal_bool.rs:35:13
+  --> tests/ui/nonminimal_bool.rs:33:13
    |
 LL |     let _ = !a && !(b && c);
    |             ^^^^^^^^^^^^^^^ help: try: `!(a || b && c)`
 
 error: this boolean expression can be simplified
-  --> tests/ui/nonminimal_bool.rs:44:13
+  --> tests/ui/nonminimal_bool.rs:42:13
    |
 LL |     let _ = a == b && c == 5 && a == b;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -57,7 +57,7 @@ LL |     let _ = a == b && c == 5;
    |             ~~~~~~~~~~~~~~~~
 
 error: this boolean expression can be simplified
-  --> tests/ui/nonminimal_bool.rs:46:13
+  --> tests/ui/nonminimal_bool.rs:44:13
    |
 LL |     let _ = a == b || c == 5 || a == b;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -70,7 +70,7 @@ LL |     let _ = a == b || c == 5;
    |             ~~~~~~~~~~~~~~~~
 
 error: this boolean expression can be simplified
-  --> tests/ui/nonminimal_bool.rs:48:13
+  --> tests/ui/nonminimal_bool.rs:46:13
    |
 LL |     let _ = a == b && c == 5 && b == a;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -83,7 +83,7 @@ LL |     let _ = a == b && c == 5;
    |             ~~~~~~~~~~~~~~~~
 
 error: this boolean expression can be simplified
-  --> tests/ui/nonminimal_bool.rs:50:13
+  --> tests/ui/nonminimal_bool.rs:48:13
    |
 LL |     let _ = a != b || !(a != b || c == d);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -96,7 +96,7 @@ LL |     let _ = a != b || c != d;
    |             ~~~~~~~~~~~~~~~~
 
 error: this boolean expression can be simplified
-  --> tests/ui/nonminimal_bool.rs:52:13
+  --> tests/ui/nonminimal_bool.rs:50:13
    |
 LL |     let _ = a != b && !(a != b && c == d);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -109,43 +109,43 @@ LL |     let _ = a != b && c != d;
    |             ~~~~~~~~~~~~~~~~
 
 error: this boolean expression can be simplified
-  --> tests/ui/nonminimal_bool.rs:83:8
+  --> tests/ui/nonminimal_bool.rs:81:8
    |
 LL |     if matches!(true, true) && true {
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(true, true)`
 
 error: this boolean expression can be simplified
-  --> tests/ui/nonminimal_bool.rs:163:8
+  --> tests/ui/nonminimal_bool.rs:161:8
    |
 LL |     if !(12 == a) {}
    |        ^^^^^^^^^^ help: try: `12 != a`
 
 error: this boolean expression can be simplified
-  --> tests/ui/nonminimal_bool.rs:164:8
+  --> tests/ui/nonminimal_bool.rs:162:8
    |
 LL |     if !(a == 12) {}
    |        ^^^^^^^^^^ help: try: `a != 12`
 
 error: this boolean expression can be simplified
-  --> tests/ui/nonminimal_bool.rs:165:8
+  --> tests/ui/nonminimal_bool.rs:163:8
    |
 LL |     if !(12 != a) {}
    |        ^^^^^^^^^^ help: try: `12 == a`
 
 error: this boolean expression can be simplified
-  --> tests/ui/nonminimal_bool.rs:166:8
+  --> tests/ui/nonminimal_bool.rs:164:8
    |
 LL |     if !(a != 12) {}
    |        ^^^^^^^^^^ help: try: `a == 12`
 
 error: this boolean expression can be simplified
-  --> tests/ui/nonminimal_bool.rs:170:8
+  --> tests/ui/nonminimal_bool.rs:168:8
    |
 LL |     if !b == true {}
    |        ^^^^^^^^^^ help: try: `b != true`
 
 error: this comparison might be written more concisely
-  --> tests/ui/nonminimal_bool.rs:170:8
+  --> tests/ui/nonminimal_bool.rs:168:8
    |
 LL |     if !b == true {}
    |        ^^^^^^^^^^ help: try simplifying it as shown: `b != true`
@@ -154,61 +154,61 @@ LL |     if !b == true {}
    = help: to override `-D warnings` add `#[allow(clippy::bool_comparison)]`
 
 error: equality checks against true are unnecessary
-  --> tests/ui/nonminimal_bool.rs:170:8
+  --> tests/ui/nonminimal_bool.rs:168:8
    |
 LL |     if !b == true {}
    |        ^^^^^^^^^^ help: try simplifying it as shown: `!b`
 
 error: this boolean expression can be simplified
-  --> tests/ui/nonminimal_bool.rs:171:8
+  --> tests/ui/nonminimal_bool.rs:169:8
    |
 LL |     if !b != true {}
    |        ^^^^^^^^^^ help: try: `b == true`
 
 error: inequality checks against true can be replaced by a negation
-  --> tests/ui/nonminimal_bool.rs:171:8
+  --> tests/ui/nonminimal_bool.rs:169:8
    |
 LL |     if !b != true {}
    |        ^^^^^^^^^^ help: try simplifying it as shown: `!(!b)`
 
 error: this boolean expression can be simplified
-  --> tests/ui/nonminimal_bool.rs:172:8
+  --> tests/ui/nonminimal_bool.rs:170:8
    |
 LL |     if true == !b {}
    |        ^^^^^^^^^^ help: try: `true != b`
 
 error: this comparison might be written more concisely
-  --> tests/ui/nonminimal_bool.rs:172:8
+  --> tests/ui/nonminimal_bool.rs:170:8
    |
 LL |     if true == !b {}
    |        ^^^^^^^^^^ help: try simplifying it as shown: `true != b`
 
 error: equality checks against true are unnecessary
-  --> tests/ui/nonminimal_bool.rs:172:8
+  --> tests/ui/nonminimal_bool.rs:170:8
    |
 LL |     if true == !b {}
    |        ^^^^^^^^^^ help: try simplifying it as shown: `!b`
 
 error: this boolean expression can be simplified
-  --> tests/ui/nonminimal_bool.rs:173:8
+  --> tests/ui/nonminimal_bool.rs:171:8
    |
 LL |     if true != !b {}
    |        ^^^^^^^^^^ help: try: `true == b`
 
 error: inequality checks against true can be replaced by a negation
-  --> tests/ui/nonminimal_bool.rs:173:8
+  --> tests/ui/nonminimal_bool.rs:171:8
    |
 LL |     if true != !b {}
    |        ^^^^^^^^^^ help: try simplifying it as shown: `!(!b)`
 
 error: this boolean expression can be simplified
-  --> tests/ui/nonminimal_bool.rs:174:8
+  --> tests/ui/nonminimal_bool.rs:172:8
    |
 LL |     if !b == !c {}
    |        ^^^^^^^^ help: try: `b == c`
 
 error: this boolean expression can be simplified
-  --> tests/ui/nonminimal_bool.rs:175:8
+  --> tests/ui/nonminimal_bool.rs:173:8
    |
 LL |     if !b != !c {}
    |        ^^^^^^^^ help: try: `b != c`
diff --git a/src/tools/clippy/tests/ui/octal_escapes.rs b/src/tools/clippy/tests/ui/octal_escapes.rs
index 3915dfdb841..f2664e2fa67 100644
--- a/src/tools/clippy/tests/ui/octal_escapes.rs
+++ b/src/tools/clippy/tests/ui/octal_escapes.rs
@@ -2,25 +2,20 @@
 #![warn(clippy::octal_escapes)]
 
 fn main() {
-    let _bad1 = "\033[0m";
-    //~^ ERROR: octal-looking escape in string literal
-    let _bad2 = b"\033[0m";
-    //~^ ERROR: octal-looking escape in byte string literal
-    let _bad3 = "\\\033[0m";
-    //~^ ERROR: octal-looking escape in string literal
+    let _bad1 = "\033[0m"; //~ octal_escapes
+    let _bad2 = b"\033[0m"; //~ octal_escapes
+    let _bad3 = "\\\033[0m"; //~ octal_escapes
     // maximum 3 digits (\012 is the escape)
-    let _bad4 = "\01234567";
-    //~^ ERROR: octal-looking escape in string literal
-    let _bad5 = "\0\03";
-    //~^ ERROR: octal-looking escape in string literal
+    let _bad4 = "\01234567"; //~ octal_escapes
+    let _bad5 = "\0\03"; //~ octal_escapes
     let _bad6 = "Text-\055\077-MoreText";
-    //~^ ERROR: octal-looking escape in string literal
+    //~^ octal_escapes
+    //~| octal_escapes
     let _bad7 = "EvenMoreText-\01\02-ShortEscapes";
-    //~^ ERROR: octal-looking escape in string literal
-    let _bad8 = "锈\01锈";
-    //~^ ERROR: octal-looking escape in string literal
-    let _bad9 = "锈\011锈";
-    //~^ ERROR: octal-looking escape in string literal
+    //~^ octal_escapes
+    //~| octal_escapes
+    let _bad8 = "锈\01锈"; //~ octal_escapes
+    let _bad9 = "锈\011锈"; //~ octal_escapes
 
     let _good1 = "\\033[0m";
     let _good2 = "\0\\0";
diff --git a/src/tools/clippy/tests/ui/octal_escapes.stderr b/src/tools/clippy/tests/ui/octal_escapes.stderr
index 7ed9ee3ae2f..9343ba64a30 100644
--- a/src/tools/clippy/tests/ui/octal_escapes.stderr
+++ b/src/tools/clippy/tests/ui/octal_escapes.stderr
@@ -1,148 +1,170 @@
-error: octal-looking escape in string literal
-  --> tests/ui/octal_escapes.rs:5:17
+error: octal-looking escape in a literal
+  --> tests/ui/octal_escapes.rs:5:18
    |
 LL |     let _bad1 = "\033[0m";
-   |                 ^^^^^^^^^
+   |                  ^^^^
    |
-   = help: octal escapes are not supported, `\0` is always a null character
+   = help: octal escapes are not supported, `\0` is always null
    = note: `-D clippy::octal-escapes` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::octal_escapes)]`
-help: if an octal escape was intended, use the hexadecimal representation instead
+help: if an octal escape is intended, use a hex escape instead
    |
 LL |     let _bad1 = "\x1b[0m";
-   |                 ~~~~~~~~~
-help: if the null character is intended, disambiguate using
+   |                  ~~~~
+help: if a null escape is intended, disambiguate using
    |
 LL |     let _bad1 = "\x0033[0m";
-   |                 ~~~~~~~~~~~
+   |                  ~~~~~~
 
-error: octal-looking escape in byte string literal
-  --> tests/ui/octal_escapes.rs:7:17
+error: octal-looking escape in a literal
+  --> tests/ui/octal_escapes.rs:6:19
    |
 LL |     let _bad2 = b"\033[0m";
-   |                 ^^^^^^^^^^
+   |                   ^^^^
    |
-   = help: octal escapes are not supported, `\0` is always a null byte
-help: if an octal escape was intended, use the hexadecimal representation instead
+help: if an octal escape is intended, use a hex escape instead
    |
 LL |     let _bad2 = b"\x1b[0m";
-   |                 ~~~~~~~~~~
-help: if the null byte is intended, disambiguate using
+   |                   ~~~~
+help: if a null escape is intended, disambiguate using
    |
 LL |     let _bad2 = b"\x0033[0m";
-   |                 ~~~~~~~~~~~~
+   |                   ~~~~~~
 
-error: octal-looking escape in string literal
-  --> tests/ui/octal_escapes.rs:9:17
+error: octal-looking escape in a literal
+  --> tests/ui/octal_escapes.rs:7:20
    |
 LL |     let _bad3 = "\\\033[0m";
-   |                 ^^^^^^^^^^^
+   |                    ^^^^
    |
-   = help: octal escapes are not supported, `\0` is always a null character
-help: if an octal escape was intended, use the hexadecimal representation instead
+help: if an octal escape is intended, use a hex escape instead
    |
 LL |     let _bad3 = "\\\x1b[0m";
-   |                 ~~~~~~~~~~~
-help: if the null character is intended, disambiguate using
+   |                    ~~~~
+help: if a null escape is intended, disambiguate using
    |
 LL |     let _bad3 = "\\\x0033[0m";
-   |                 ~~~~~~~~~~~~~
+   |                    ~~~~~~
 
-error: octal-looking escape in string literal
-  --> tests/ui/octal_escapes.rs:12:17
+error: octal-looking escape in a literal
+  --> tests/ui/octal_escapes.rs:9:18
    |
 LL |     let _bad4 = "\01234567";
-   |                 ^^^^^^^^^^^
+   |                  ^^^^
    |
-   = help: octal escapes are not supported, `\0` is always a null character
-help: if an octal escape was intended, use the hexadecimal representation instead
+help: if an octal escape is intended, use a hex escape instead
    |
 LL |     let _bad4 = "\x0a34567";
-   |                 ~~~~~~~~~~~
-help: if the null character is intended, disambiguate using
+   |                  ~~~~
+help: if a null escape is intended, disambiguate using
    |
 LL |     let _bad4 = "\x001234567";
-   |                 ~~~~~~~~~~~~~
+   |                  ~~~~~~
 
-error: octal-looking escape in string literal
-  --> tests/ui/octal_escapes.rs:14:17
+error: octal-looking escape in a literal
+  --> tests/ui/octal_escapes.rs:10:20
    |
 LL |     let _bad5 = "\0\03";
-   |                 ^^^^^^^
+   |                    ^^^
    |
-   = help: octal escapes are not supported, `\0` is always a null character
-help: if an octal escape was intended, use the hexadecimal representation instead
+help: if an octal escape is intended, use a hex escape instead
    |
 LL |     let _bad5 = "\0\x03";
-   |                 ~~~~~~~~
-help: if the null character is intended, disambiguate using
+   |                    ~~~~
+help: if a null escape is intended, disambiguate using
    |
-LL |     let _bad5 = "\0\x003";
-   |                 ~~~~~~~~~
+LL |     let _bad5 = "\0\x0003";
+   |                    ~~~~~~
 
-error: octal-looking escape in string literal
-  --> tests/ui/octal_escapes.rs:16:17
+error: octal-looking escape in a literal
+  --> tests/ui/octal_escapes.rs:11:23
    |
 LL |     let _bad6 = "Text-\055\077-MoreText";
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^
    |
-   = help: octal escapes are not supported, `\0` is always a null character
-help: if an octal escape was intended, use the hexadecimal representation instead
+help: if an octal escape is intended, use a hex escape instead
    |
-LL |     let _bad6 = "Text-\x2d\x3f-MoreText";
-   |                 ~~~~~~~~~~~~~~~~~~~~~~~~
-help: if the null character is intended, disambiguate using
+LL |     let _bad6 = "Text-\x2d\077-MoreText";
+   |                       ~~~~
+help: if a null escape is intended, disambiguate using
    |
-LL |     let _bad6 = "Text-\x0055\x0077-MoreText";
-   |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     let _bad6 = "Text-\x0055\077-MoreText";
+   |                       ~~~~~~
 
-error: octal-looking escape in string literal
-  --> tests/ui/octal_escapes.rs:18:17
+error: octal-looking escape in a literal
+  --> tests/ui/octal_escapes.rs:11:27
+   |
+LL |     let _bad6 = "Text-\055\077-MoreText";
+   |                           ^^^^
+   |
+help: if an octal escape is intended, use a hex escape instead
+   |
+LL |     let _bad6 = "Text-\055\x3f-MoreText";
+   |                           ~~~~
+help: if a null escape is intended, disambiguate using
+   |
+LL |     let _bad6 = "Text-\055\x0077-MoreText";
+   |                           ~~~~~~
+
+error: octal-looking escape in a literal
+  --> tests/ui/octal_escapes.rs:14:31
+   |
+LL |     let _bad7 = "EvenMoreText-\01\02-ShortEscapes";
+   |                               ^^^
+   |
+help: if an octal escape is intended, use a hex escape instead
+   |
+LL |     let _bad7 = "EvenMoreText-\x01\02-ShortEscapes";
+   |                               ~~~~
+help: if a null escape is intended, disambiguate using
+   |
+LL |     let _bad7 = "EvenMoreText-\x0001\02-ShortEscapes";
+   |                               ~~~~~~
+
+error: octal-looking escape in a literal
+  --> tests/ui/octal_escapes.rs:14:34
    |
 LL |     let _bad7 = "EvenMoreText-\01\02-ShortEscapes";
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                  ^^^
    |
-   = help: octal escapes are not supported, `\0` is always a null character
-help: if an octal escape was intended, use the hexadecimal representation instead
+help: if an octal escape is intended, use a hex escape instead
    |
-LL |     let _bad7 = "EvenMoreText-\x01\x02-ShortEscapes";
-   |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-help: if the null character is intended, disambiguate using
+LL |     let _bad7 = "EvenMoreText-\01\x02-ShortEscapes";
+   |                                  ~~~~
+help: if a null escape is intended, disambiguate using
    |
-LL |     let _bad7 = "EvenMoreText-\x001\x002-ShortEscapes";
-   |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     let _bad7 = "EvenMoreText-\01\x0002-ShortEscapes";
+   |                                  ~~~~~~
 
-error: octal-looking escape in string literal
-  --> tests/ui/octal_escapes.rs:20:17
+error: octal-looking escape in a literal
+  --> tests/ui/octal_escapes.rs:17:19
    |
 LL |     let _bad8 = "锈\01锈";
-   |                 ^^^^^^^^^
+   |                    ^^^
    |
-   = help: octal escapes are not supported, `\0` is always a null character
-help: if an octal escape was intended, use the hexadecimal representation instead
+help: if an octal escape is intended, use a hex escape instead
    |
 LL |     let _bad8 = "锈\x01锈";
-   |                 ~~~~~~~~~~
-help: if the null character is intended, disambiguate using
+   |                    ~~~~
+help: if a null escape is intended, disambiguate using
    |
-LL |     let _bad8 = "锈\x001锈";
-   |                 ~~~~~~~~~~~
+LL |     let _bad8 = "锈\x0001锈";
+   |                    ~~~~~~
 
-error: octal-looking escape in string literal
-  --> tests/ui/octal_escapes.rs:22:17
+error: octal-looking escape in a literal
+  --> tests/ui/octal_escapes.rs:18:19
    |
 LL |     let _bad9 = "锈\011锈";
-   |                 ^^^^^^^^^^
+   |                    ^^^^
    |
-   = help: octal escapes are not supported, `\0` is always a null character
-help: if an octal escape was intended, use the hexadecimal representation instead
+help: if an octal escape is intended, use a hex escape instead
    |
 LL |     let _bad9 = "锈\x09锈";
-   |                 ~~~~~~~~~~
-help: if the null character is intended, disambiguate using
+   |                    ~~~~
+help: if a null escape is intended, disambiguate using
    |
 LL |     let _bad9 = "锈\x0011锈";
-   |                 ~~~~~~~~~~~~
+   |                    ~~~~~~
 
-error: aborting due to 9 previous errors
+error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.fixed b/src/tools/clippy/tests/ui/option_if_let_else.fixed
index eeab801b7da..0ac89bf0d8e 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.fixed
+++ b/src/tools/clippy/tests/ui/option_if_let_else.fixed
@@ -4,7 +4,8 @@
     clippy::equatable_if_let,
     clippy::let_unit_value,
     clippy::redundant_locals,
-    clippy::manual_unwrap_or_default
+    clippy::manual_unwrap_or_default,
+    clippy::manual_unwrap_or
 )]
 
 fn bad1(string: Option<&str>) -> (bool, &str) {
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.rs b/src/tools/clippy/tests/ui/option_if_let_else.rs
index 3e5b96d7c31..b4f1b2cd1f7 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.rs
+++ b/src/tools/clippy/tests/ui/option_if_let_else.rs
@@ -4,7 +4,8 @@
     clippy::equatable_if_let,
     clippy::let_unit_value,
     clippy::redundant_locals,
-    clippy::manual_unwrap_or_default
+    clippy::manual_unwrap_or_default,
+    clippy::manual_unwrap_or
 )]
 
 fn bad1(string: Option<&str>) -> (bool, &str) {
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.stderr b/src/tools/clippy/tests/ui/option_if_let_else.stderr
index f5359a0c34f..37ef791edb0 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.stderr
+++ b/src/tools/clippy/tests/ui/option_if_let_else.stderr
@@ -1,5 +1,5 @@
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:11:5
+  --> tests/ui/option_if_let_else.rs:12:5
    |
 LL | /     if let Some(x) = string {
 LL | |         (true, x)
@@ -12,19 +12,19 @@ LL | |     }
    = help: to override `-D warnings` add `#[allow(clippy::option_if_let_else)]`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:29:13
+  --> tests/ui/option_if_let_else.rs:30:13
    |
 LL |     let _ = if let Some(s) = *string { s.len() } else { 0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:30:13
+  --> tests/ui/option_if_let_else.rs:31:13
    |
 LL |     let _ = if let Some(s) = &num { s } else { &0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:31:13
+  --> tests/ui/option_if_let_else.rs:32:13
    |
 LL |       let _ = if let Some(s) = &mut num {
    |  _____________^
@@ -44,13 +44,13 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:37:13
+  --> tests/ui/option_if_let_else.rs:38:13
    |
 LL |     let _ = if let Some(ref s) = num { s } else { &0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:38:13
+  --> tests/ui/option_if_let_else.rs:39:13
    |
 LL |       let _ = if let Some(mut s) = num {
    |  _____________^
@@ -70,7 +70,7 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:44:13
+  --> tests/ui/option_if_let_else.rs:45:13
    |
 LL |       let _ = if let Some(ref mut s) = num {
    |  _____________^
@@ -90,7 +90,7 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:53:5
+  --> tests/ui/option_if_let_else.rs:54:5
    |
 LL | /     if let Some(x) = arg {
 LL | |         let y = x * x;
@@ -109,7 +109,7 @@ LL +     })
    |
 
 error: use Option::map_or_else instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:66:13
+  --> tests/ui/option_if_let_else.rs:67:13
    |
 LL |       let _ = if let Some(x) = arg {
    |  _____________^
@@ -121,7 +121,7 @@ LL | |     };
    | |_____^ help: try: `arg.map_or_else(side_effect, |x| x)`
 
 error: use Option::map_or_else instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:75:13
+  --> tests/ui/option_if_let_else.rs:76:13
    |
 LL |       let _ = if let Some(x) = arg {
    |  _____________^
@@ -144,7 +144,7 @@ LL ~     }, |x| x * x * x * x);
    |
 
 error: use Option::map_or_else instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:108:13
+  --> tests/ui/option_if_let_else.rs:109:13
    |
 LL | /             if let Some(idx) = s.find('.') {
 LL | |                 vec![s[..idx].to_string(), s[idx..].to_string()]
@@ -154,7 +154,7 @@ LL | |             }
    | |_____________^ help: try: `s.find('.').map_or_else(|| vec![s.to_string()], |idx| vec![s[..idx].to_string(), s[idx..].to_string()])`
 
 error: use Option::map_or_else instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:119:5
+  --> tests/ui/option_if_let_else.rs:120:5
    |
 LL | /     if let Ok(binding) = variable {
 LL | |         println!("Ok {binding}");
@@ -177,13 +177,13 @@ LL +     })
    |
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:143:13
+  --> tests/ui/option_if_let_else.rs:144:13
    |
 LL |     let _ = if let Some(x) = optional { x + 2 } else { 5 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:153:13
+  --> tests/ui/option_if_let_else.rs:154:13
    |
 LL |       let _ = if let Some(x) = Some(0) {
    |  _____________^
@@ -205,13 +205,13 @@ LL ~         });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:181:13
+  --> tests/ui/option_if_let_else.rs:182:13
    |
 LL |     let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or(s.len(), |x| s.len() + x)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:185:13
+  --> tests/ui/option_if_let_else.rs:186:13
    |
 LL |       let _ = if let Some(x) = Some(0) {
    |  _____________^
@@ -231,7 +231,7 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:224:13
+  --> tests/ui/option_if_let_else.rs:225:13
    |
 LL |       let _ = match s {
    |  _____________^
@@ -241,7 +241,7 @@ LL | |     };
    | |_____^ help: try: `s.map_or(1, |string| string.len())`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:228:13
+  --> tests/ui/option_if_let_else.rs:229:13
    |
 LL |       let _ = match Some(10) {
    |  _____________^
@@ -251,7 +251,7 @@ LL | |     };
    | |_____^ help: try: `Some(10).map_or(5, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:234:13
+  --> tests/ui/option_if_let_else.rs:235:13
    |
 LL |       let _ = match res {
    |  _____________^
@@ -261,7 +261,7 @@ LL | |     };
    | |_____^ help: try: `res.map_or(1, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:238:13
+  --> tests/ui/option_if_let_else.rs:239:13
    |
 LL |       let _ = match res {
    |  _____________^
@@ -271,13 +271,13 @@ LL | |     };
    | |_____^ help: try: `res.map_or(1, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:242:13
+  --> tests/ui/option_if_let_else.rs:243:13
    |
 LL |     let _ = if let Ok(a) = res { a + 1 } else { 5 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or(5, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:259:17
+  --> tests/ui/option_if_let_else.rs:260:17
    |
 LL |           let _ = match initial {
    |  _________________^
@@ -287,7 +287,7 @@ LL | |         };
    | |_________^ help: try: `initial.as_ref().map_or(42, |value| do_something(value))`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:266:17
+  --> tests/ui/option_if_let_else.rs:267:17
    |
 LL |           let _ = match initial {
    |  _________________^
@@ -297,7 +297,7 @@ LL | |         };
    | |_________^ help: try: `initial.as_mut().map_or(42, |value| do_something2(value))`
 
 error: use Option::map_or_else instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:289:24
+  --> tests/ui/option_if_let_else.rs:290:24
    |
 LL |       let mut _hashmap = if let Some(hm) = &opt {
    |  ________________________^
@@ -308,7 +308,7 @@ LL | |     };
    | |_____^ help: try: `opt.as_ref().map_or_else(HashMap::new, |hm| hm.clone())`
 
 error: use Option::map_or_else instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:295:19
+  --> tests/ui/option_if_let_else.rs:296:19
    |
 LL |     let mut _hm = if let Some(hm) = &opt { hm.clone() } else { new_map!() };
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.as_ref().map_or_else(|| new_map!(), |hm| hm.clone())`
diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed
index 7657ef470c5..c76f7a81843 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.fixed
+++ b/src/tools/clippy/tests/ui/or_fun_call.fixed
@@ -98,7 +98,7 @@ fn or_fun_call() {
 
     let opt = Some(1);
     let hello = "Hello";
-    let _ = opt.ok_or(format!("{} world.", hello));
+    let _ = opt.ok_or_else(|| format!("{} world.", hello));
 
     // index
     let map = HashMap::<u64, u64>::new();
diff --git a/src/tools/clippy/tests/ui/or_fun_call.stderr b/src/tools/clippy/tests/ui/or_fun_call.stderr
index b5a30f29923..3070db22fc5 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.stderr
+++ b/src/tools/clippy/tests/ui/or_fun_call.stderr
@@ -100,6 +100,12 @@ error: use of `unwrap_or` to construct default value
 LL |     let _ = stringy.unwrap_or(String::new());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
+error: use of `ok_or` followed by a function call
+  --> tests/ui/or_fun_call.rs:101:17
+   |
+LL |     let _ = opt.ok_or(format!("{} world.", hello));
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ok_or_else(|| format!("{} world.", hello))`
+
 error: use of `unwrap_or` followed by a function call
   --> tests/ui/or_fun_call.rs:105:21
    |
@@ -190,5 +196,5 @@ error: use of `unwrap_or_else` to construct default value
 LL |         let _ = stringy.unwrap_or_else(String::new);
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
-error: aborting due to 31 previous errors
+error: aborting due to 32 previous errors
 
diff --git a/src/tools/clippy/tests/ui/overly_complex_bool_expr.fixed b/src/tools/clippy/tests/ui/overly_complex_bool_expr.fixed
index 439b1145431..b21e91aa3ad 100644
--- a/src/tools/clippy/tests/ui/overly_complex_bool_expr.fixed
+++ b/src/tools/clippy/tests/ui/overly_complex_bool_expr.fixed
@@ -1,4 +1,3 @@
-#![feature(lint_reasons)]
 #![allow(unused, clippy::diverging_sub_expression)]
 #![warn(clippy::overly_complex_bool_expr)]
 
diff --git a/src/tools/clippy/tests/ui/overly_complex_bool_expr.rs b/src/tools/clippy/tests/ui/overly_complex_bool_expr.rs
index b96fd1adf11..35ef0a1240a 100644
--- a/src/tools/clippy/tests/ui/overly_complex_bool_expr.rs
+++ b/src/tools/clippy/tests/ui/overly_complex_bool_expr.rs
@@ -1,4 +1,3 @@
-#![feature(lint_reasons)]
 #![allow(unused, clippy::diverging_sub_expression)]
 #![warn(clippy::overly_complex_bool_expr)]
 
diff --git a/src/tools/clippy/tests/ui/overly_complex_bool_expr.stderr b/src/tools/clippy/tests/ui/overly_complex_bool_expr.stderr
index 21dd5ade535..5a754236fe4 100644
--- a/src/tools/clippy/tests/ui/overly_complex_bool_expr.stderr
+++ b/src/tools/clippy/tests/ui/overly_complex_bool_expr.stderr
@@ -1,11 +1,11 @@
 error: this boolean expression contains a logic bug
-  --> tests/ui/overly_complex_bool_expr.rs:11:13
+  --> tests/ui/overly_complex_bool_expr.rs:10:13
    |
 LL |     let _ = a && b || a;
    |             ^^^^^^^^^^^ help: it would look like the following: `a`
    |
 help: this expression can be optimized out by applying boolean operations to the outer expression
-  --> tests/ui/overly_complex_bool_expr.rs:11:18
+  --> tests/ui/overly_complex_bool_expr.rs:10:18
    |
 LL |     let _ = a && b || a;
    |                  ^
@@ -13,49 +13,49 @@ LL |     let _ = a && b || a;
    = help: to override `-D warnings` add `#[allow(clippy::overly_complex_bool_expr)]`
 
 error: this boolean expression contains a logic bug
-  --> tests/ui/overly_complex_bool_expr.rs:14:13
+  --> tests/ui/overly_complex_bool_expr.rs:13:13
    |
 LL |     let _ = false && a;
    |             ^^^^^^^^^^ help: it would look like the following: `false`
    |
 help: this expression can be optimized out by applying boolean operations to the outer expression
-  --> tests/ui/overly_complex_bool_expr.rs:14:22
+  --> tests/ui/overly_complex_bool_expr.rs:13:22
    |
 LL |     let _ = false && a;
    |                      ^
 
 error: this boolean expression contains a logic bug
-  --> tests/ui/overly_complex_bool_expr.rs:25:13
+  --> tests/ui/overly_complex_bool_expr.rs:24:13
    |
 LL |     let _ = a == b && a != b;
    |             ^^^^^^^^^^^^^^^^ help: it would look like the following: `false`
    |
 help: this expression can be optimized out by applying boolean operations to the outer expression
-  --> tests/ui/overly_complex_bool_expr.rs:25:13
+  --> tests/ui/overly_complex_bool_expr.rs:24:13
    |
 LL |     let _ = a == b && a != b;
    |             ^^^^^^
 
 error: this boolean expression contains a logic bug
-  --> tests/ui/overly_complex_bool_expr.rs:27:13
+  --> tests/ui/overly_complex_bool_expr.rs:26:13
    |
 LL |     let _ = a < b && a >= b;
    |             ^^^^^^^^^^^^^^^ help: it would look like the following: `false`
    |
 help: this expression can be optimized out by applying boolean operations to the outer expression
-  --> tests/ui/overly_complex_bool_expr.rs:27:13
+  --> tests/ui/overly_complex_bool_expr.rs:26:13
    |
 LL |     let _ = a < b && a >= b;
    |             ^^^^^
 
 error: this boolean expression contains a logic bug
-  --> tests/ui/overly_complex_bool_expr.rs:29:13
+  --> tests/ui/overly_complex_bool_expr.rs:28:13
    |
 LL |     let _ = a > b && a <= b;
    |             ^^^^^^^^^^^^^^^ help: it would look like the following: `false`
    |
 help: this expression can be optimized out by applying boolean operations to the outer expression
-  --> tests/ui/overly_complex_bool_expr.rs:29:13
+  --> tests/ui/overly_complex_bool_expr.rs:28:13
    |
 LL |     let _ = a > b && a <= b;
    |             ^^^^^
diff --git a/src/tools/clippy/tests/ui/ptr_arg.rs b/src/tools/clippy/tests/ui/ptr_arg.rs
index 5d6e488972c..e6ef6268121 100644
--- a/src/tools/clippy/tests/ui/ptr_arg.rs
+++ b/src/tools/clippy/tests/ui/ptr_arg.rs
@@ -1,4 +1,3 @@
-#![feature(lint_reasons)]
 #![allow(
     unused,
     clippy::many_single_char_names,
diff --git a/src/tools/clippy/tests/ui/ptr_arg.stderr b/src/tools/clippy/tests/ui/ptr_arg.stderr
index 0342130c992..1848ef80fc4 100644
--- a/src/tools/clippy/tests/ui/ptr_arg.stderr
+++ b/src/tools/clippy/tests/ui/ptr_arg.stderr
@@ -1,5 +1,5 @@
 error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do
-  --> tests/ui/ptr_arg.rs:14:14
+  --> tests/ui/ptr_arg.rs:13:14
    |
 LL | fn do_vec(x: &Vec<i64>) {
    |              ^^^^^^^^^ help: change this to: `&[i64]`
@@ -8,49 +8,49 @@ LL | fn do_vec(x: &Vec<i64>) {
    = help: to override `-D warnings` add `#[allow(clippy::ptr_arg)]`
 
 error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do
-  --> tests/ui/ptr_arg.rs:20:18
+  --> tests/ui/ptr_arg.rs:19:18
    |
 LL | fn do_vec_mut(x: &mut Vec<i64>) {
    |                  ^^^^^^^^^^^^^ help: change this to: `&mut [i64]`
 
 error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do
-  --> tests/ui/ptr_arg.rs:25:19
+  --> tests/ui/ptr_arg.rs:24:19
    |
 LL | fn do_vec_mut2(x: &mut Vec<i64>) {
    |                   ^^^^^^^^^^^^^ help: change this to: `&mut [i64]`
 
 error: writing `&String` instead of `&str` involves a new object where a slice will do
-  --> tests/ui/ptr_arg.rs:31:14
+  --> tests/ui/ptr_arg.rs:30:14
    |
 LL | fn do_str(x: &String) {
    |              ^^^^^^^ help: change this to: `&str`
 
 error: writing `&mut String` instead of `&mut str` involves a new object where a slice will do
-  --> tests/ui/ptr_arg.rs:36:18
+  --> tests/ui/ptr_arg.rs:35:18
    |
 LL | fn do_str_mut(x: &mut String) {
    |                  ^^^^^^^^^^^ help: change this to: `&mut str`
 
 error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
-  --> tests/ui/ptr_arg.rs:41:15
+  --> tests/ui/ptr_arg.rs:40:15
    |
 LL | fn do_path(x: &PathBuf) {
    |               ^^^^^^^^ help: change this to: `&Path`
 
 error: writing `&mut PathBuf` instead of `&mut Path` involves a new object where a slice will do
-  --> tests/ui/ptr_arg.rs:46:19
+  --> tests/ui/ptr_arg.rs:45:19
    |
 LL | fn do_path_mut(x: &mut PathBuf) {
    |                   ^^^^^^^^^^^^ help: change this to: `&mut Path`
 
 error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do
-  --> tests/ui/ptr_arg.rs:55:18
+  --> tests/ui/ptr_arg.rs:54:18
    |
 LL |     fn do_vec(x: &Vec<i64>);
    |                  ^^^^^^^^^ help: change this to: `&[i64]`
 
 error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do
-  --> tests/ui/ptr_arg.rs:69:14
+  --> tests/ui/ptr_arg.rs:68:14
    |
 LL | fn cloned(x: &Vec<u8>) -> Vec<u8> {
    |              ^^^^^^^^
@@ -68,7 +68,7 @@ LL ~     x.to_owned()
    |
 
 error: writing `&String` instead of `&str` involves a new object where a slice will do
-  --> tests/ui/ptr_arg.rs:79:18
+  --> tests/ui/ptr_arg.rs:78:18
    |
 LL | fn str_cloned(x: &String) -> String {
    |                  ^^^^^^^
@@ -85,7 +85,7 @@ LL ~     x.to_owned()
    |
 
 error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
-  --> tests/ui/ptr_arg.rs:88:19
+  --> tests/ui/ptr_arg.rs:87:19
    |
 LL | fn path_cloned(x: &PathBuf) -> PathBuf {
    |                   ^^^^^^^^
@@ -102,7 +102,7 @@ LL ~     x.to_path_buf()
    |
 
 error: writing `&String` instead of `&str` involves a new object where a slice will do
-  --> tests/ui/ptr_arg.rs:97:44
+  --> tests/ui/ptr_arg.rs:96:44
    |
 LL | fn false_positive_capacity(x: &Vec<u8>, y: &String) {
    |                                            ^^^^^^^
@@ -117,19 +117,19 @@ LL ~     let c = y;
    |
 
 error: using a reference to `Cow` is not recommended
-  --> tests/ui/ptr_arg.rs:112:25
+  --> tests/ui/ptr_arg.rs:111:25
    |
 LL | fn test_cow_with_ref(c: &Cow<[i32]>) {}
    |                         ^^^^^^^^^^^ help: change this to: `&[i32]`
 
 error: writing `&String` instead of `&str` involves a new object where a slice will do
-  --> tests/ui/ptr_arg.rs:142:66
+  --> tests/ui/ptr_arg.rs:141:66
    |
 LL |     fn some_allowed(#[allow(clippy::ptr_arg)] _v: &Vec<u32>, _s: &String) {}
    |                                                                  ^^^^^^^ help: change this to: `&str`
 
 error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do
-  --> tests/ui/ptr_arg.rs:172:21
+  --> tests/ui/ptr_arg.rs:171:21
    |
 LL |     fn foo_vec(vec: &Vec<u8>) {
    |                     ^^^^^^^^
@@ -143,7 +143,7 @@ LL ~         let _ = vec.to_owned().clone();
    |
 
 error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
-  --> tests/ui/ptr_arg.rs:178:23
+  --> tests/ui/ptr_arg.rs:177:23
    |
 LL |     fn foo_path(path: &PathBuf) {
    |                       ^^^^^^^^
@@ -157,7 +157,7 @@ LL ~         let _ = path.to_path_buf().clone();
    |
 
 error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
-  --> tests/ui/ptr_arg.rs:184:21
+  --> tests/ui/ptr_arg.rs:183:21
    |
 LL |     fn foo_str(str: &PathBuf) {
    |                     ^^^^^^^^
@@ -171,43 +171,43 @@ LL ~         let _ = str.to_path_buf().clone();
    |
 
 error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do
-  --> tests/ui/ptr_arg.rs:191:29
+  --> tests/ui/ptr_arg.rs:190:29
    |
 LL | fn mut_vec_slice_methods(v: &mut Vec<u32>) {
    |                             ^^^^^^^^^^^^^ help: change this to: `&mut [u32]`
 
 error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do
-  --> tests/ui/ptr_arg.rs:254:17
+  --> tests/ui/ptr_arg.rs:253:17
    |
 LL | fn dyn_trait(a: &mut Vec<u32>, b: &mut String, c: &mut PathBuf) {
    |                 ^^^^^^^^^^^^^ help: change this to: `&mut [u32]`
 
 error: writing `&mut String` instead of `&mut str` involves a new object where a slice will do
-  --> tests/ui/ptr_arg.rs:254:35
+  --> tests/ui/ptr_arg.rs:253:35
    |
 LL | fn dyn_trait(a: &mut Vec<u32>, b: &mut String, c: &mut PathBuf) {
    |                                   ^^^^^^^^^^^ help: change this to: `&mut str`
 
 error: writing `&mut PathBuf` instead of `&mut Path` involves a new object where a slice will do
-  --> tests/ui/ptr_arg.rs:254:51
+  --> tests/ui/ptr_arg.rs:253:51
    |
 LL | fn dyn_trait(a: &mut Vec<u32>, b: &mut String, c: &mut PathBuf) {
    |                                                   ^^^^^^^^^^^^ help: change this to: `&mut Path`
 
 error: using a reference to `Cow` is not recommended
-  --> tests/ui/ptr_arg.rs:280:39
+  --> tests/ui/ptr_arg.rs:279:39
    |
 LL |     fn cow_elided_lifetime<'a>(input: &'a Cow<str>) -> &'a str {
    |                                       ^^^^^^^^^^^^ help: change this to: `&str`
 
 error: using a reference to `Cow` is not recommended
-  --> tests/ui/ptr_arg.rs:286:36
+  --> tests/ui/ptr_arg.rs:285:36
    |
 LL |     fn cow_bad_ret_ty_1<'a>(input: &'a Cow<'a, str>) -> &'static str {
    |                                    ^^^^^^^^^^^^^^^^ help: change this to: `&str`
 
 error: using a reference to `Cow` is not recommended
-  --> tests/ui/ptr_arg.rs:290:40
+  --> tests/ui/ptr_arg.rs:289:40
    |
 LL |     fn cow_bad_ret_ty_2<'a, 'b>(input: &'a Cow<'a, str>) -> &'b str {
    |                                        ^^^^^^^^^^^^^^^^ help: change this to: `&str`
diff --git a/src/tools/clippy/tests/ui/redundant_clone.fixed b/src/tools/clippy/tests/ui/redundant_clone.fixed
index 867f5b21017..1f79b5e5360 100644
--- a/src/tools/clippy/tests/ui/redundant_clone.fixed
+++ b/src/tools/clippy/tests/ui/redundant_clone.fixed
@@ -1,5 +1,4 @@
 // rustfix-only-machine-applicable
-#![feature(lint_reasons)]
 #![warn(clippy::redundant_clone)]
 #![allow(
     clippy::drop_non_drop,
diff --git a/src/tools/clippy/tests/ui/redundant_clone.rs b/src/tools/clippy/tests/ui/redundant_clone.rs
index adcbd01e819..6909faebc99 100644
--- a/src/tools/clippy/tests/ui/redundant_clone.rs
+++ b/src/tools/clippy/tests/ui/redundant_clone.rs
@@ -1,5 +1,4 @@
 // rustfix-only-machine-applicable
-#![feature(lint_reasons)]
 #![warn(clippy::redundant_clone)]
 #![allow(
     clippy::drop_non_drop,
diff --git a/src/tools/clippy/tests/ui/redundant_clone.stderr b/src/tools/clippy/tests/ui/redundant_clone.stderr
index 3c37288f550..d66972bcb5b 100644
--- a/src/tools/clippy/tests/ui/redundant_clone.stderr
+++ b/src/tools/clippy/tests/ui/redundant_clone.stderr
@@ -1,11 +1,11 @@
 error: redundant clone
-  --> tests/ui/redundant_clone.rs:15:42
+  --> tests/ui/redundant_clone.rs:14:42
    |
 LL |     let _s = ["lorem", "ipsum"].join(" ").to_string();
    |                                          ^^^^^^^^^^^^ help: remove this
    |
 note: this value is dropped without further use
-  --> tests/ui/redundant_clone.rs:15:14
+  --> tests/ui/redundant_clone.rs:14:14
    |
 LL |     let _s = ["lorem", "ipsum"].join(" ").to_string();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -13,169 +13,169 @@ LL |     let _s = ["lorem", "ipsum"].join(" ").to_string();
    = help: to override `-D warnings` add `#[allow(clippy::redundant_clone)]`
 
 error: redundant clone
-  --> tests/ui/redundant_clone.rs:18:15
+  --> tests/ui/redundant_clone.rs:17:15
    |
 LL |     let _s = s.clone();
    |               ^^^^^^^^ help: remove this
    |
 note: this value is dropped without further use
-  --> tests/ui/redundant_clone.rs:18:14
+  --> tests/ui/redundant_clone.rs:17:14
    |
 LL |     let _s = s.clone();
    |              ^
 
 error: redundant clone
-  --> tests/ui/redundant_clone.rs:21:15
+  --> tests/ui/redundant_clone.rs:20:15
    |
 LL |     let _s = s.to_string();
    |               ^^^^^^^^^^^^ help: remove this
    |
 note: this value is dropped without further use
-  --> tests/ui/redundant_clone.rs:21:14
+  --> tests/ui/redundant_clone.rs:20:14
    |
 LL |     let _s = s.to_string();
    |              ^
 
 error: redundant clone
-  --> tests/ui/redundant_clone.rs:24:15
+  --> tests/ui/redundant_clone.rs:23:15
    |
 LL |     let _s = s.to_owned();
    |               ^^^^^^^^^^^ help: remove this
    |
 note: this value is dropped without further use
-  --> tests/ui/redundant_clone.rs:24:14
+  --> tests/ui/redundant_clone.rs:23:14
    |
 LL |     let _s = s.to_owned();
    |              ^
 
 error: redundant clone
-  --> tests/ui/redundant_clone.rs:26:42
+  --> tests/ui/redundant_clone.rs:25:42
    |
 LL |     let _s = Path::new("/a/b/").join("c").to_owned();
    |                                          ^^^^^^^^^^^ help: remove this
    |
 note: this value is dropped without further use
-  --> tests/ui/redundant_clone.rs:26:14
+  --> tests/ui/redundant_clone.rs:25:14
    |
 LL |     let _s = Path::new("/a/b/").join("c").to_owned();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: redundant clone
-  --> tests/ui/redundant_clone.rs:28:42
+  --> tests/ui/redundant_clone.rs:27:42
    |
 LL |     let _s = Path::new("/a/b/").join("c").to_path_buf();
    |                                          ^^^^^^^^^^^^^^ help: remove this
    |
 note: this value is dropped without further use
-  --> tests/ui/redundant_clone.rs:28:14
+  --> tests/ui/redundant_clone.rs:27:14
    |
 LL |     let _s = Path::new("/a/b/").join("c").to_path_buf();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: redundant clone
-  --> tests/ui/redundant_clone.rs:30:29
+  --> tests/ui/redundant_clone.rs:29:29
    |
 LL |     let _s = OsString::new().to_owned();
    |                             ^^^^^^^^^^^ help: remove this
    |
 note: this value is dropped without further use
-  --> tests/ui/redundant_clone.rs:30:14
+  --> tests/ui/redundant_clone.rs:29:14
    |
 LL |     let _s = OsString::new().to_owned();
    |              ^^^^^^^^^^^^^^^
 
 error: redundant clone
-  --> tests/ui/redundant_clone.rs:32:29
+  --> tests/ui/redundant_clone.rs:31:29
    |
 LL |     let _s = OsString::new().to_os_string();
    |                             ^^^^^^^^^^^^^^^ help: remove this
    |
 note: this value is dropped without further use
-  --> tests/ui/redundant_clone.rs:32:14
+  --> tests/ui/redundant_clone.rs:31:14
    |
 LL |     let _s = OsString::new().to_os_string();
    |              ^^^^^^^^^^^^^^^
 
 error: redundant clone
-  --> tests/ui/redundant_clone.rs:43:19
+  --> tests/ui/redundant_clone.rs:42:19
    |
 LL |     let _t = tup.0.clone();
    |                   ^^^^^^^^ help: remove this
    |
 note: this value is dropped without further use
-  --> tests/ui/redundant_clone.rs:43:14
+  --> tests/ui/redundant_clone.rs:42:14
    |
 LL |     let _t = tup.0.clone();
    |              ^^^^^
 
 error: redundant clone
-  --> tests/ui/redundant_clone.rs:75:25
+  --> tests/ui/redundant_clone.rs:74:25
    |
 LL |     if b { (a.clone(), a.clone()) } else { (Alpha, a) }
    |                         ^^^^^^^^ help: remove this
    |
 note: this value is dropped without further use
-  --> tests/ui/redundant_clone.rs:75:24
+  --> tests/ui/redundant_clone.rs:74:24
    |
 LL |     if b { (a.clone(), a.clone()) } else { (Alpha, a) }
    |                        ^
 
 error: redundant clone
-  --> tests/ui/redundant_clone.rs:132:15
+  --> tests/ui/redundant_clone.rs:131:15
    |
 LL |     let _s = s.clone();
    |               ^^^^^^^^ help: remove this
    |
 note: this value is dropped without further use
-  --> tests/ui/redundant_clone.rs:132:14
+  --> tests/ui/redundant_clone.rs:131:14
    |
 LL |     let _s = s.clone();
    |              ^
 
 error: redundant clone
-  --> tests/ui/redundant_clone.rs:133:15
+  --> tests/ui/redundant_clone.rs:132:15
    |
 LL |     let _t = t.clone();
    |               ^^^^^^^^ help: remove this
    |
 note: this value is dropped without further use
-  --> tests/ui/redundant_clone.rs:133:14
+  --> tests/ui/redundant_clone.rs:132:14
    |
 LL |     let _t = t.clone();
    |              ^
 
 error: redundant clone
-  --> tests/ui/redundant_clone.rs:143:19
+  --> tests/ui/redundant_clone.rs:142:19
    |
 LL |         let _f = f.clone();
    |                   ^^^^^^^^ help: remove this
    |
 note: this value is dropped without further use
-  --> tests/ui/redundant_clone.rs:143:18
+  --> tests/ui/redundant_clone.rs:142:18
    |
 LL |         let _f = f.clone();
    |                  ^
 
 error: redundant clone
-  --> tests/ui/redundant_clone.rs:155:14
+  --> tests/ui/redundant_clone.rs:154:14
    |
 LL |     let y = x.clone().join("matthias");
    |              ^^^^^^^^ help: remove this
    |
 note: cloned value is neither consumed nor mutated
-  --> tests/ui/redundant_clone.rs:155:13
+  --> tests/ui/redundant_clone.rs:154:13
    |
 LL |     let y = x.clone().join("matthias");
    |             ^^^^^^^^^
 
 error: redundant clone
-  --> tests/ui/redundant_clone.rs:209:11
+  --> tests/ui/redundant_clone.rs:208:11
    |
 LL |     foo(&x.clone(), move || {
    |           ^^^^^^^^ help: remove this
    |
 note: this value is dropped without further use
-  --> tests/ui/redundant_clone.rs:209:10
+  --> tests/ui/redundant_clone.rs:208:10
    |
 LL |     foo(&x.clone(), move || {
    |          ^
diff --git a/src/tools/clippy/tests/ui/ref_binding_to_reference.rs b/src/tools/clippy/tests/ui/ref_binding_to_reference.rs
index a4444c95e33..001ed311949 100644
--- a/src/tools/clippy/tests/ui/ref_binding_to_reference.rs
+++ b/src/tools/clippy/tests/ui/ref_binding_to_reference.rs
@@ -1,6 +1,5 @@
 // FIXME: run-rustfix waiting on multi-span suggestions
 //@no-rustfix
-#![feature(lint_reasons)]
 #![warn(clippy::ref_binding_to_reference)]
 #![allow(clippy::needless_borrowed_reference, clippy::explicit_auto_deref)]
 
diff --git a/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr b/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr
index 96886f80265..25ab9822382 100644
--- a/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr
+++ b/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr
@@ -1,5 +1,5 @@
 error: this pattern creates a reference to a reference
-  --> tests/ui/ref_binding_to_reference.rs:31:14
+  --> tests/ui/ref_binding_to_reference.rs:30:14
    |
 LL |         Some(ref x) => x,
    |              ^^^^^
@@ -12,7 +12,7 @@ LL |         Some(x) => &x,
    |              ~     ~~
 
 error: this pattern creates a reference to a reference
-  --> tests/ui/ref_binding_to_reference.rs:39:14
+  --> tests/ui/ref_binding_to_reference.rs:38:14
    |
 LL |         Some(ref x) => {
    |              ^^^^^
@@ -27,7 +27,7 @@ LL ~             &x
    |
 
 error: this pattern creates a reference to a reference
-  --> tests/ui/ref_binding_to_reference.rs:50:14
+  --> tests/ui/ref_binding_to_reference.rs:49:14
    |
 LL |         Some(ref x) => m2!(x),
    |              ^^^^^
@@ -38,7 +38,7 @@ LL |         Some(x) => m2!(&x),
    |              ~         ~~
 
 error: this pattern creates a reference to a reference
-  --> tests/ui/ref_binding_to_reference.rs:56:15
+  --> tests/ui/ref_binding_to_reference.rs:55:15
    |
 LL |     let _ = |&ref x: &&String| {
    |               ^^^^^
@@ -51,7 +51,7 @@ LL ~         let _: &&String = &x;
    |
 
 error: this pattern creates a reference to a reference
-  --> tests/ui/ref_binding_to_reference.rs:63:12
+  --> tests/ui/ref_binding_to_reference.rs:62:12
    |
 LL | fn f2<'a>(&ref x: &&'a String) -> &'a String {
    |            ^^^^^
@@ -65,7 +65,7 @@ LL ~     x
    |
 
 error: this pattern creates a reference to a reference
-  --> tests/ui/ref_binding_to_reference.rs:71:11
+  --> tests/ui/ref_binding_to_reference.rs:70:11
    |
 LL |     fn f(&ref x: &&String) {
    |           ^^^^^
@@ -78,7 +78,7 @@ LL ~         let _: &&String = &x;
    |
 
 error: this pattern creates a reference to a reference
-  --> tests/ui/ref_binding_to_reference.rs:80:11
+  --> tests/ui/ref_binding_to_reference.rs:79:11
    |
 LL |     fn f(&ref x: &&String) {
    |           ^^^^^
diff --git a/src/tools/clippy/tests/ui/same_name_method.rs b/src/tools/clippy/tests/ui/same_name_method.rs
index 26b1a299ba1..ba876c2b5a3 100644
--- a/src/tools/clippy/tests/ui/same_name_method.rs
+++ b/src/tools/clippy/tests/ui/same_name_method.rs
@@ -1,4 +1,3 @@
-#![feature(lint_reasons)]
 #![warn(clippy::same_name_method)]
 #![allow(dead_code, non_camel_case_types)]
 
diff --git a/src/tools/clippy/tests/ui/same_name_method.stderr b/src/tools/clippy/tests/ui/same_name_method.stderr
index 6c87a64b505..fefdb5c9c23 100644
--- a/src/tools/clippy/tests/ui/same_name_method.stderr
+++ b/src/tools/clippy/tests/ui/same_name_method.stderr
@@ -1,11 +1,11 @@
 error: method's name is the same as an existing method in a trait
-  --> tests/ui/same_name_method.rs:21:13
+  --> tests/ui/same_name_method.rs:20:13
    |
 LL |             fn foo() {}
    |             ^^^^^^^^^^^
    |
 note: existing `foo` defined here
-  --> tests/ui/same_name_method.rs:26:13
+  --> tests/ui/same_name_method.rs:25:13
    |
 LL |             fn foo() {}
    |             ^^^^^^^^^^^
@@ -13,62 +13,62 @@ LL |             fn foo() {}
    = help: to override `-D warnings` add `#[allow(clippy::same_name_method)]`
 
 error: method's name is the same as an existing method in a trait
-  --> tests/ui/same_name_method.rs:36:13
+  --> tests/ui/same_name_method.rs:35:13
    |
 LL |             fn clone() {}
    |             ^^^^^^^^^^^^^
    |
 note: existing `clone` defined here
-  --> tests/ui/same_name_method.rs:32:18
+  --> tests/ui/same_name_method.rs:31:18
    |
 LL |         #[derive(Clone)]
    |                  ^^^^^
    = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: method's name is the same as an existing method in a trait
-  --> tests/ui/same_name_method.rs:47:13
+  --> tests/ui/same_name_method.rs:46:13
    |
 LL |             fn foo() {}
    |             ^^^^^^^^^^^
    |
 note: existing `foo` defined here
-  --> tests/ui/same_name_method.rs:52:13
+  --> tests/ui/same_name_method.rs:51:13
    |
 LL |             fn foo() {}
    |             ^^^^^^^^^^^
 
 error: method's name is the same as an existing method in a trait
-  --> tests/ui/same_name_method.rs:62:13
+  --> tests/ui/same_name_method.rs:61:13
    |
 LL |             fn foo() {}
    |             ^^^^^^^^^^^
    |
 note: existing `foo` defined here
-  --> tests/ui/same_name_method.rs:66:9
+  --> tests/ui/same_name_method.rs:65:9
    |
 LL |         impl T1 for S {}
    |         ^^^^^^^^^^^^^^^^
 
 error: method's name is the same as an existing method in a trait
-  --> tests/ui/same_name_method.rs:75:13
+  --> tests/ui/same_name_method.rs:74:13
    |
 LL |             fn foo() {}
    |             ^^^^^^^^^^^
    |
 note: existing `foo` defined here
-  --> tests/ui/same_name_method.rs:80:9
+  --> tests/ui/same_name_method.rs:79:9
    |
 LL |         impl T1 for S {}
    |         ^^^^^^^^^^^^^^^^
 
 error: method's name is the same as an existing method in a trait
-  --> tests/ui/same_name_method.rs:75:13
+  --> tests/ui/same_name_method.rs:74:13
    |
 LL |             fn foo() {}
    |             ^^^^^^^^^^^
    |
 note: existing `foo` defined here
-  --> tests/ui/same_name_method.rs:82:9
+  --> tests/ui/same_name_method.rs:81:9
    |
 LL |         impl T2 for S {}
    |         ^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/significant_drop_tightening.stderr b/src/tools/clippy/tests/ui/significant_drop_tightening.stderr
index f818a14cbe6..5fc66279f00 100644
--- a/src/tools/clippy/tests/ui/significant_drop_tightening.stderr
+++ b/src/tools/clippy/tests/ui/significant_drop_tightening.stderr
@@ -64,7 +64,6 @@ LL +         let rslt0 = mutex.lock().unwrap().abs();
 help: remove separated single usage
    |
 LL -         let rslt0 = lock.abs();
-LL +         
    |
 
 error: temporary with significant `Drop` can be early dropped
@@ -88,7 +87,6 @@ LL +         mutex.lock().unwrap().clear();
 help: remove separated single usage
    |
 LL -         lock.clear();
-LL +         
    |
 
 error: aborting due to 4 previous errors
diff --git a/src/tools/clippy/tests/ui/tabs_in_doc_comments.stderr b/src/tools/clippy/tests/ui/tabs_in_doc_comments.stderr
index 23d5dcd3a8d..aef6c391452 100644
--- a/src/tools/clippy/tests/ui/tabs_in_doc_comments.stderr
+++ b/src/tools/clippy/tests/ui/tabs_in_doc_comments.stderr
@@ -1,53 +1,53 @@
 error: using tabs in doc comments is not recommended
-  --> tests/ui/tabs_in_doc_comments.rs:10:9
+  --> tests/ui/tabs_in_doc_comments.rs:6:5
    |
-LL |     ///     - First String:
-   |         ^^^^ help: consider using four spaces per tab
+LL | ///     - first        one
+   |     ^^^^ help: consider using four spaces per tab
    |
    = note: `-D clippy::tabs-in-doc-comments` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::tabs_in_doc_comments)]`
 
 error: using tabs in doc comments is not recommended
-  --> tests/ui/tabs_in_doc_comments.rs:11:9
+  --> tests/ui/tabs_in_doc_comments.rs:6:13
    |
-LL |     ///         - needs to be inside here
-   |         ^^^^^^^^ help: consider using four spaces per tab
+LL | ///     - first        one
+   |                ^^^^^^^^ help: consider using four spaces per tab
 
 error: using tabs in doc comments is not recommended
-  --> tests/ui/tabs_in_doc_comments.rs:14:9
+  --> tests/ui/tabs_in_doc_comments.rs:7:5
    |
-LL |     ///     - Second String:
-   |         ^^^^ help: consider using four spaces per tab
+LL | ///     - second    one
+   |     ^^^^ help: consider using four spaces per tab
 
 error: using tabs in doc comments is not recommended
-  --> tests/ui/tabs_in_doc_comments.rs:15:9
+  --> tests/ui/tabs_in_doc_comments.rs:7:14
    |
-LL |     ///         - needs to be inside here
-   |         ^^^^^^^^ help: consider using four spaces per tab
+LL | ///     - second    one
+   |                 ^^^^ help: consider using four spaces per tab
 
 error: using tabs in doc comments is not recommended
-  --> tests/ui/tabs_in_doc_comments.rs:6:5
+  --> tests/ui/tabs_in_doc_comments.rs:10:9
    |
-LL | ///     - first        one
-   |     ^^^^ help: consider using four spaces per tab
+LL |     ///     - First String:
+   |         ^^^^ help: consider using four spaces per tab
 
 error: using tabs in doc comments is not recommended
-  --> tests/ui/tabs_in_doc_comments.rs:6:13
+  --> tests/ui/tabs_in_doc_comments.rs:11:9
    |
-LL | ///     - first        one
-   |                ^^^^^^^^ help: consider using four spaces per tab
+LL |     ///         - needs to be inside here
+   |         ^^^^^^^^ help: consider using four spaces per tab
 
 error: using tabs in doc comments is not recommended
-  --> tests/ui/tabs_in_doc_comments.rs:7:5
+  --> tests/ui/tabs_in_doc_comments.rs:14:9
    |
-LL | ///     - second    one
-   |     ^^^^ help: consider using four spaces per tab
+LL |     ///     - Second String:
+   |         ^^^^ help: consider using four spaces per tab
 
 error: using tabs in doc comments is not recommended
-  --> tests/ui/tabs_in_doc_comments.rs:7:14
+  --> tests/ui/tabs_in_doc_comments.rs:15:9
    |
-LL | ///     - second    one
-   |                 ^^^^ help: consider using four spaces per tab
+LL |     ///         - needs to be inside here
+   |         ^^^^^^^^ help: consider using four spaces per tab
 
 error: aborting due to 8 previous errors
 
diff --git a/src/tools/clippy/tests/ui/transmute.rs b/src/tools/clippy/tests/ui/transmute.rs
index be6e071767d..46629526367 100644
--- a/src/tools/clippy/tests/ui/transmute.rs
+++ b/src/tools/clippy/tests/ui/transmute.rs
@@ -1,3 +1,5 @@
+#![feature(f128)]
+#![feature(f16)]
 #![allow(
     dead_code,
     clippy::borrow_as_ptr,
@@ -117,20 +119,34 @@ fn int_to_bool() {
 #[warn(clippy::transmute_int_to_float)]
 mod int_to_float {
     fn test() {
+        let _: f16 = unsafe { std::mem::transmute(0_u16) };
+        //~^ ERROR: transmute from a `u16` to a `f16`
+        //~| NOTE: `-D clippy::transmute-int-to-float` implied by `-D warnings`
+        let _: f16 = unsafe { std::mem::transmute(0_i16) };
+        //~^ ERROR: transmute from a `i16` to a `f16`
         let _: f32 = unsafe { std::mem::transmute(0_u32) };
         //~^ ERROR: transmute from a `u32` to a `f32`
-        //~| NOTE: `-D clippy::transmute-int-to-float` implied by `-D warnings`
         let _: f32 = unsafe { std::mem::transmute(0_i32) };
         //~^ ERROR: transmute from a `i32` to a `f32`
         let _: f64 = unsafe { std::mem::transmute(0_u64) };
         //~^ ERROR: transmute from a `u64` to a `f64`
         let _: f64 = unsafe { std::mem::transmute(0_i64) };
         //~^ ERROR: transmute from a `i64` to a `f64`
+        let _: f128 = unsafe { std::mem::transmute(0_u128) };
+        //~^ ERROR: transmute from a `u128` to a `f128`
+        let _: f128 = unsafe { std::mem::transmute(0_i128) };
+        //~^ ERROR: transmute from a `i128` to a `f128`
     }
 
     mod issue_5747 {
+        const VALUE16: f16 = unsafe { std::mem::transmute(0_u16) };
         const VALUE32: f32 = unsafe { std::mem::transmute(0_u32) };
         const VALUE64: f64 = unsafe { std::mem::transmute(0_i64) };
+        const VALUE128: f128 = unsafe { std::mem::transmute(0_i128) };
+
+        const fn from_bits_16(v: i16) -> f16 {
+            unsafe { std::mem::transmute(v) }
+        }
 
         const fn from_bits_32(v: i32) -> f32 {
             unsafe { std::mem::transmute(v) }
@@ -139,6 +155,10 @@ mod int_to_float {
         const fn from_bits_64(v: u64) -> f64 {
             unsafe { std::mem::transmute(v) }
         }
+
+        const fn from_bits_128(v: u128) -> f128 {
+            unsafe { std::mem::transmute(v) }
+        }
     }
 }
 
@@ -158,10 +178,15 @@ mod num_to_bytes {
             //~^ ERROR: transmute from a `i32` to a `[u8; 4]`
             let _: [u8; 16] = std::mem::transmute(0i128);
             //~^ ERROR: transmute from a `i128` to a `[u8; 16]`
+
+            let _: [u8; 2] = std::mem::transmute(0.0f16);
+            //~^ ERROR: transmute from a `f16` to a `[u8; 2]`
             let _: [u8; 4] = std::mem::transmute(0.0f32);
             //~^ ERROR: transmute from a `f32` to a `[u8; 4]`
             let _: [u8; 8] = std::mem::transmute(0.0f64);
             //~^ ERROR: transmute from a `f64` to a `[u8; 8]`
+            let _: [u8; 16] = std::mem::transmute(0.0f128);
+            //~^ ERROR: transmute from a `f128` to a `[u8; 16]`
         }
     }
     const fn test_const() {
@@ -178,8 +203,11 @@ mod num_to_bytes {
             //~^ ERROR: transmute from a `i32` to a `[u8; 4]`
             let _: [u8; 16] = std::mem::transmute(0i128);
             //~^ ERROR: transmute from a `i128` to a `[u8; 16]`
+
+            let _: [u8; 2] = std::mem::transmute(0.0f16);
             let _: [u8; 4] = std::mem::transmute(0.0f32);
             let _: [u8; 8] = std::mem::transmute(0.0f64);
+            let _: [u8; 16] = std::mem::transmute(0.0f128);
         }
     }
 }
diff --git a/src/tools/clippy/tests/ui/transmute.stderr b/src/tools/clippy/tests/ui/transmute.stderr
index 375e8f19dd6..0072f62962a 100644
--- a/src/tools/clippy/tests/ui/transmute.stderr
+++ b/src/tools/clippy/tests/ui/transmute.stderr
@@ -1,5 +1,5 @@
 error: transmute from a reference to a pointer
-  --> tests/ui/transmute.rs:29:23
+  --> tests/ui/transmute.rs:31:23
    |
 LL |     let _: *const T = core::intrinsics::transmute(t);
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T`
@@ -8,61 +8,61 @@ LL |     let _: *const T = core::intrinsics::transmute(t);
    = help: to override `-D warnings` add `#[allow(clippy::useless_transmute)]`
 
 error: transmute from a reference to a pointer
-  --> tests/ui/transmute.rs:33:21
+  --> tests/ui/transmute.rs:35:21
    |
 LL |     let _: *mut T = core::intrinsics::transmute(t);
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *mut T`
 
 error: transmute from a reference to a pointer
-  --> tests/ui/transmute.rs:36:23
+  --> tests/ui/transmute.rs:38:23
    |
 LL |     let _: *const U = core::intrinsics::transmute(t);
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *const U`
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
-  --> tests/ui/transmute.rs:43:27
+  --> tests/ui/transmute.rs:45:27
    |
 LL |         let _: Vec<i32> = core::intrinsics::transmute(my_vec());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
-  --> tests/ui/transmute.rs:46:27
+  --> tests/ui/transmute.rs:48:27
    |
 LL |         let _: Vec<i32> = core::mem::transmute(my_vec());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
-  --> tests/ui/transmute.rs:49:27
+  --> tests/ui/transmute.rs:51:27
    |
 LL |         let _: Vec<i32> = std::intrinsics::transmute(my_vec());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
-  --> tests/ui/transmute.rs:52:27
+  --> tests/ui/transmute.rs:54:27
    |
 LL |         let _: Vec<i32> = std::mem::transmute(my_vec());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
-  --> tests/ui/transmute.rs:55:27
+  --> tests/ui/transmute.rs:57:27
    |
 LL |         let _: Vec<i32> = my_transmute(my_vec());
    |                           ^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from an integer to a pointer
-  --> tests/ui/transmute.rs:58:31
+  --> tests/ui/transmute.rs:60:31
    |
 LL |         let _: *const usize = std::mem::transmute(5_isize);
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `5_isize as *const usize`
 
 error: transmute from an integer to a pointer
-  --> tests/ui/transmute.rs:63:31
+  --> tests/ui/transmute.rs:65:31
    |
 LL |         let _: *const usize = std::mem::transmute(1 + 1usize);
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(1 + 1usize) as *const usize`
 
 error: transmute from a type (`*const Usize`) to the type that it points to (`Usize`)
-  --> tests/ui/transmute.rs:95:24
+  --> tests/ui/transmute.rs:97:24
    |
 LL |         let _: Usize = core::intrinsics::transmute(int_const_ptr);
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -71,25 +71,25 @@ LL |         let _: Usize = core::intrinsics::transmute(int_const_ptr);
    = help: to override `-D warnings` add `#[allow(clippy::crosspointer_transmute)]`
 
 error: transmute from a type (`*mut Usize`) to the type that it points to (`Usize`)
-  --> tests/ui/transmute.rs:99:24
+  --> tests/ui/transmute.rs:101:24
    |
 LL |         let _: Usize = core::intrinsics::transmute(int_mut_ptr);
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`Usize`) to a pointer to that type (`*const Usize`)
-  --> tests/ui/transmute.rs:102:31
+  --> tests/ui/transmute.rs:104:31
    |
 LL |         let _: *const Usize = core::intrinsics::transmute(my_int());
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`)
-  --> tests/ui/transmute.rs:105:29
+  --> tests/ui/transmute.rs:107:29
    |
 LL |         let _: *mut Usize = core::intrinsics::transmute(my_int());
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a `u8` to a `bool`
-  --> tests/ui/transmute.rs:112:28
+  --> tests/ui/transmute.rs:114:28
    |
 LL |     let _: bool = unsafe { std::mem::transmute(0_u8) };
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `0_u8 != 0`
@@ -97,35 +97,59 @@ 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 `u32` to a `f32`
-  --> tests/ui/transmute.rs:120:31
+error: transmute from a `u16` to a `f16`
+  --> tests/ui/transmute.rs:122:31
    |
-LL |         let _: f32 = unsafe { std::mem::transmute(0_u32) };
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)`
+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:127: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:123:31
+  --> tests/ui/transmute.rs:129: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:125:31
+  --> tests/ui/transmute.rs:131: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:127:31
+  --> tests/ui/transmute.rs:133: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:135: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:137:32
+   |
+LL |         let _: f128 = unsafe { std::mem::transmute(0_i128) };
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_i128 as u128)`
+
 error: transmute from a `u8` to a `[u8; 1]`
-  --> tests/ui/transmute.rs:148:30
+  --> tests/ui/transmute.rs:168:30
    |
 LL |             let _: [u8; 1] = std::mem::transmute(0u8);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()`
@@ -134,85 +158,97 @@ LL |             let _: [u8; 1] = std::mem::transmute(0u8);
    = 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:151:30
+  --> tests/ui/transmute.rs:171: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:153:31
+  --> tests/ui/transmute.rs:173: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:155:30
+  --> tests/ui/transmute.rs:175: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:157:30
+  --> tests/ui/transmute.rs:177: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:159:31
+  --> tests/ui/transmute.rs:179: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:182: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:161:30
+  --> tests/ui/transmute.rs:184: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:163:30
+  --> tests/ui/transmute.rs:186: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:188: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:169:30
+  --> tests/ui/transmute.rs:194: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:171:30
+  --> tests/ui/transmute.rs:196: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:173:31
+  --> tests/ui/transmute.rs:198: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:175:30
+  --> tests/ui/transmute.rs:200: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:177:30
+  --> tests/ui/transmute.rs:202: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:179:31
+  --> tests/ui/transmute.rs:204:31
    |
 LL |             let _: [u8; 16] = std::mem::transmute(0i128);
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()`
 
 error: transmute from a `&[u8]` to a `&str`
-  --> tests/ui/transmute.rs:190:28
+  --> tests/ui/transmute.rs:218:28
    |
 LL |     let _: &str = unsafe { std::mem::transmute(B) };
    |                            ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(B).unwrap()`
@@ -221,16 +257,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:193:32
+  --> tests/ui/transmute.rs:221: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:195:30
+  --> tests/ui/transmute.rs:223:30
    |
 LL |     const _: &str = unsafe { std::mem::transmute(B) };
    |                              ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_unchecked(B)`
 
-error: aborting due to 36 previous errors
+error: aborting due to 42 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
index 82d5f7fdca1..4361a7407d1 100644
--- a/src/tools/clippy/tests/ui/transmute_float_to_int.fixed
+++ b/src/tools/clippy/tests/ui/transmute_float_to_int.fixed
@@ -1,5 +1,7 @@
 #![warn(clippy::transmute_float_to_int)]
 #![allow(clippy::missing_transmute_annotations)]
+#![feature(f128)]
+#![feature(f16)]
 
 fn float_to_int() {
     let _: u32 = unsafe { 1f32.to_bits() };
@@ -18,8 +20,14 @@ fn float_to_int() {
 }
 
 mod issue_5747 {
+    const VALUE16: i16 = unsafe { std::mem::transmute(1f16) };
     const VALUE32: i32 = unsafe { std::mem::transmute(1f32) };
     const VALUE64: u64 = unsafe { std::mem::transmute(1f64) };
+    const VALUE128: u128 = unsafe { std::mem::transmute(1f128) };
+
+    const fn to_bits_16(v: f16) -> u16 {
+        unsafe { std::mem::transmute(v) }
+    }
 
     const fn to_bits_32(v: f32) -> u32 {
         unsafe { std::mem::transmute(v) }
@@ -28,6 +36,10 @@ mod issue_5747 {
     const fn to_bits_64(v: f64) -> i64 {
         unsafe { std::mem::transmute(v) }
     }
+
+    const fn to_bits_128(v: f128) -> i128 {
+        unsafe { std::mem::transmute(v) }
+    }
 }
 
 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
index 9f056330adf..363ce0bcb16 100644
--- a/src/tools/clippy/tests/ui/transmute_float_to_int.rs
+++ b/src/tools/clippy/tests/ui/transmute_float_to_int.rs
@@ -1,5 +1,7 @@
 #![warn(clippy::transmute_float_to_int)]
 #![allow(clippy::missing_transmute_annotations)]
+#![feature(f128)]
+#![feature(f16)]
 
 fn float_to_int() {
     let _: u32 = unsafe { std::mem::transmute(1f32) };
@@ -18,8 +20,14 @@ fn float_to_int() {
 }
 
 mod issue_5747 {
+    const VALUE16: i16 = unsafe { std::mem::transmute(1f16) };
     const VALUE32: i32 = unsafe { std::mem::transmute(1f32) };
     const VALUE64: u64 = unsafe { std::mem::transmute(1f64) };
+    const VALUE128: u128 = unsafe { std::mem::transmute(1f128) };
+
+    const fn to_bits_16(v: f16) -> u16 {
+        unsafe { std::mem::transmute(v) }
+    }
 
     const fn to_bits_32(v: f32) -> u32 {
         unsafe { std::mem::transmute(v) }
@@ -28,6 +36,10 @@ mod issue_5747 {
     const fn to_bits_64(v: f64) -> i64 {
         unsafe { std::mem::transmute(v) }
     }
+
+    const fn to_bits_128(v: f128) -> i128 {
+        unsafe { std::mem::transmute(v) }
+    }
 }
 
 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
index ac3aae5f8b7..9cac75f72cd 100644
--- a/src/tools/clippy/tests/ui/transmute_float_to_int.stderr
+++ b/src/tools/clippy/tests/ui/transmute_float_to_int.stderr
@@ -1,5 +1,5 @@
 error: transmute from a `f32` to a `u32`
-  --> tests/ui/transmute_float_to_int.rs:5:27
+  --> tests/ui/transmute_float_to_int.rs:7:27
    |
 LL |     let _: u32 = unsafe { std::mem::transmute(1f32) };
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f32.to_bits()`
@@ -8,31 +8,31 @@ LL |     let _: u32 = unsafe { std::mem::transmute(1f32) };
    = 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:8:27
+  --> 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:10:27
+  --> tests/ui/transmute_float_to_int.rs:12: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:12:27
+  --> tests/ui/transmute_float_to_int.rs:14: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:14:27
+  --> tests/ui/transmute_float_to_int.rs:16: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:16:27
+  --> tests/ui/transmute_float_to_int.rs:18:27
    |
 LL |     let _: u64 = unsafe { std::mem::transmute(-1.0) };
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-1.0f64).to_bits()`
diff --git a/src/tools/clippy/tests/ui/unnecessary_clippy_cfg.stderr b/src/tools/clippy/tests/ui/unnecessary_clippy_cfg.stderr
index 16a86165295..01f842a657d 100644
--- a/src/tools/clippy/tests/ui/unnecessary_clippy_cfg.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_clippy_cfg.stderr
@@ -1,61 +1,61 @@
 error: no need to put clippy lints behind a `clippy` cfg
-  --> tests/ui/unnecessary_clippy_cfg.rs:13:1
+  --> tests/ui/unnecessary_clippy_cfg.rs:4:1
    |
-LL | #[cfg_attr(clippy, deny(clippy::non_minimal_cfg))]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `#[deny(clippy::non_minimal_cfg)]`
+LL | #![cfg_attr(clippy, deny(clippy::non_minimal_cfg))]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `#![deny(clippy::non_minimal_cfg)]`
    |
    = note: `-D clippy::unnecessary-clippy-cfg` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::unnecessary_clippy_cfg)]`
 
 error: no need to put clippy lints behind a `clippy` cfg
-  --> tests/ui/unnecessary_clippy_cfg.rs:15:36
+  --> tests/ui/unnecessary_clippy_cfg.rs:6:37
    |
-LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))]
-   |                                    ^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))]
+   |                                     ^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: write instead: `#[deny(clippy::non_minimal_cfg)]`
+   = note: write instead: `#![deny(clippy::non_minimal_cfg)]`
 
 error: no need to put clippy lints behind a `clippy` cfg
-  --> tests/ui/unnecessary_clippy_cfg.rs:17:36
+  --> tests/ui/unnecessary_clippy_cfg.rs:8:37
    |
-LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))]
-   |                                    ^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))]
+   |                                     ^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: write instead: `#[deny(clippy::non_minimal_cfg)]`
+   = note: write instead: `#![deny(clippy::non_minimal_cfg)]`
 
 error: no need to put clippy lints behind a `clippy` cfg
-  --> tests/ui/unnecessary_clippy_cfg.rs:19:1
+  --> tests/ui/unnecessary_clippy_cfg.rs:10:1
    |
-LL | #[cfg_attr(clippy, deny(clippy::non_minimal_cfg))]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `#[deny(clippy::non_minimal_cfg)]`
+LL | #![cfg_attr(clippy, deny(clippy::non_minimal_cfg))]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `#![deny(clippy::non_minimal_cfg)]`
 
 error: no need to put clippy lints behind a `clippy` cfg
-  --> tests/ui/unnecessary_clippy_cfg.rs:4:1
+  --> tests/ui/unnecessary_clippy_cfg.rs:13:1
    |
-LL | #![cfg_attr(clippy, deny(clippy::non_minimal_cfg))]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `#![deny(clippy::non_minimal_cfg)]`
+LL | #[cfg_attr(clippy, deny(clippy::non_minimal_cfg))]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `#[deny(clippy::non_minimal_cfg)]`
 
 error: no need to put clippy lints behind a `clippy` cfg
-  --> tests/ui/unnecessary_clippy_cfg.rs:6:37
+  --> tests/ui/unnecessary_clippy_cfg.rs:15:36
    |
-LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))]
-   |                                     ^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))]
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: write instead: `#![deny(clippy::non_minimal_cfg)]`
+   = note: write instead: `#[deny(clippy::non_minimal_cfg)]`
 
 error: no need to put clippy lints behind a `clippy` cfg
-  --> tests/ui/unnecessary_clippy_cfg.rs:8:37
+  --> tests/ui/unnecessary_clippy_cfg.rs:17:36
    |
-LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))]
-   |                                     ^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))]
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: write instead: `#![deny(clippy::non_minimal_cfg)]`
+   = note: write instead: `#[deny(clippy::non_minimal_cfg)]`
 
 error: no need to put clippy lints behind a `clippy` cfg
-  --> tests/ui/unnecessary_clippy_cfg.rs:10:1
+  --> tests/ui/unnecessary_clippy_cfg.rs:19:1
    |
-LL | #![cfg_attr(clippy, deny(clippy::non_minimal_cfg))]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `#![deny(clippy::non_minimal_cfg)]`
+LL | #[cfg_attr(clippy, deny(clippy::non_minimal_cfg))]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `#[deny(clippy::non_minimal_cfg)]`
 
 error: duplicated attribute
   --> tests/ui/unnecessary_clippy_cfg.rs:8:26
diff --git a/src/tools/clippy/tests/ui/unnecessary_min_or_max.fixed b/src/tools/clippy/tests/ui/unnecessary_min_or_max.fixed
new file mode 100644
index 00000000000..392f6dd1fee
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_min_or_max.fixed
@@ -0,0 +1,67 @@
+//@aux-build:external_consts.rs
+
+#![allow(unused)]
+#![warn(clippy::unnecessary_min_or_max)]
+#![allow(clippy::identity_op)]
+
+extern crate external_consts;
+
+const X: i32 = 1;
+
+fn main() {
+    // Both are Literals
+    let _ = (-6_i32);
+    let _ = 9;
+    let _ = 6;
+    let _ = 9_u32;
+    let _ = 6;
+    let _ = 7_u8;
+
+    let x: u32 = 42;
+    // unsigned with zero
+    let _ = 0;
+    let _ = x;
+    let _ = 0_u32;
+    let _ = x;
+
+    let x: i32 = 42;
+    // signed MIN
+    let _ = i32::MIN;
+    let _ = x;
+    let _ = i32::MIN;
+    let _ = x;
+
+    let _ = i32::MIN - 0;
+    let _ = x;
+
+    let _ = i32::MIN - 0;
+
+    // The below cases shouldn't be lint
+    let mut min = u32::MAX;
+    for _ in 0..1000 {
+        min = min.min(random_u32());
+    }
+
+    let _ = 2.min(external_consts::MAGIC_NUMBER);
+    let _ = 2.max(external_consts::MAGIC_NUMBER);
+    let _ = external_consts::MAGIC_NUMBER.min(2);
+    let _ = external_consts::MAGIC_NUMBER.max(2);
+
+    let _ = X.min(external_consts::MAGIC_NUMBER);
+    let _ = X.max(external_consts::MAGIC_NUMBER);
+    let _ = external_consts::MAGIC_NUMBER.min(X);
+    let _ = external_consts::MAGIC_NUMBER.max(X);
+
+    let _ = X.max(12);
+    let _ = X.min(12);
+    let _ = 12.min(X);
+    let _ = 12.max(X);
+    let _ = (X + 1).max(12);
+    let _ = (X + 1).min(12);
+    let _ = 12.min(X - 1);
+    let _ = 12.max(X - 1);
+}
+fn random_u32() -> u32 {
+    // random number generator
+    0
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_min_or_max.rs b/src/tools/clippy/tests/ui/unnecessary_min_or_max.rs
new file mode 100644
index 00000000000..b03755e6d23
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_min_or_max.rs
@@ -0,0 +1,67 @@
+//@aux-build:external_consts.rs
+
+#![allow(unused)]
+#![warn(clippy::unnecessary_min_or_max)]
+#![allow(clippy::identity_op)]
+
+extern crate external_consts;
+
+const X: i32 = 1;
+
+fn main() {
+    // Both are Literals
+    let _ = (-6_i32).min(9);
+    let _ = (-6_i32).max(9);
+    let _ = 9_u32.min(6);
+    let _ = 9_u32.max(6);
+    let _ = 6.min(7_u8);
+    let _ = 6.max(7_u8);
+
+    let x: u32 = 42;
+    // unsigned with zero
+    let _ = 0.min(x);
+    let _ = 0.max(x);
+    let _ = x.min(0_u32);
+    let _ = x.max(0_u32);
+
+    let x: i32 = 42;
+    // signed MIN
+    let _ = i32::MIN.min(x);
+    let _ = i32::MIN.max(x);
+    let _ = x.min(i32::MIN);
+    let _ = x.max(i32::MIN);
+
+    let _ = x.min(i32::MIN - 0);
+    let _ = x.max(i32::MIN);
+
+    let _ = x.min(i32::MIN - 0);
+
+    // The below cases shouldn't be lint
+    let mut min = u32::MAX;
+    for _ in 0..1000 {
+        min = min.min(random_u32());
+    }
+
+    let _ = 2.min(external_consts::MAGIC_NUMBER);
+    let _ = 2.max(external_consts::MAGIC_NUMBER);
+    let _ = external_consts::MAGIC_NUMBER.min(2);
+    let _ = external_consts::MAGIC_NUMBER.max(2);
+
+    let _ = X.min(external_consts::MAGIC_NUMBER);
+    let _ = X.max(external_consts::MAGIC_NUMBER);
+    let _ = external_consts::MAGIC_NUMBER.min(X);
+    let _ = external_consts::MAGIC_NUMBER.max(X);
+
+    let _ = X.max(12);
+    let _ = X.min(12);
+    let _ = 12.min(X);
+    let _ = 12.max(X);
+    let _ = (X + 1).max(12);
+    let _ = (X + 1).min(12);
+    let _ = 12.min(X - 1);
+    let _ = 12.max(X - 1);
+}
+fn random_u32() -> u32 {
+    // random number generator
+    0
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_min_or_max.stderr b/src/tools/clippy/tests/ui/unnecessary_min_or_max.stderr
new file mode 100644
index 00000000000..f5cd31fbaf2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_min_or_max.stderr
@@ -0,0 +1,107 @@
+error: `(-6_i32)` is never greater than `9` and has therefore no effect
+  --> tests/ui/unnecessary_min_or_max.rs:13:13
+   |
+LL |     let _ = (-6_i32).min(9);
+   |             ^^^^^^^^^^^^^^^ help: try: `(-6_i32)`
+   |
+   = note: `-D clippy::unnecessary-min-or-max` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::unnecessary_min_or_max)]`
+
+error: `(-6_i32)` is never greater than `9` and has therefore no effect
+  --> tests/ui/unnecessary_min_or_max.rs:14:13
+   |
+LL |     let _ = (-6_i32).max(9);
+   |             ^^^^^^^^^^^^^^^ help: try: `9`
+
+error: `9_u32` is never smaller than `6` and has therefore no effect
+  --> tests/ui/unnecessary_min_or_max.rs:15:13
+   |
+LL |     let _ = 9_u32.min(6);
+   |             ^^^^^^^^^^^^ help: try: `6`
+
+error: `9_u32` is never smaller than `6` and has therefore no effect
+  --> tests/ui/unnecessary_min_or_max.rs:16:13
+   |
+LL |     let _ = 9_u32.max(6);
+   |             ^^^^^^^^^^^^ help: try: `9_u32`
+
+error: `6` is never greater than `7_u8` and has therefore no effect
+  --> tests/ui/unnecessary_min_or_max.rs:17:13
+   |
+LL |     let _ = 6.min(7_u8);
+   |             ^^^^^^^^^^^ help: try: `6`
+
+error: `6` is never greater than `7_u8` and has therefore no effect
+  --> tests/ui/unnecessary_min_or_max.rs:18:13
+   |
+LL |     let _ = 6.max(7_u8);
+   |             ^^^^^^^^^^^ help: try: `7_u8`
+
+error: `0` is never greater than `x` and has therefore no effect
+  --> tests/ui/unnecessary_min_or_max.rs:22:13
+   |
+LL |     let _ = 0.min(x);
+   |             ^^^^^^^^ help: try: `0`
+
+error: `0` is never greater than `x` and has therefore no effect
+  --> tests/ui/unnecessary_min_or_max.rs:23:13
+   |
+LL |     let _ = 0.max(x);
+   |             ^^^^^^^^ help: try: `x`
+
+error: `x` is never smaller than `0_u32` and has therefore no effect
+  --> tests/ui/unnecessary_min_or_max.rs:24:13
+   |
+LL |     let _ = x.min(0_u32);
+   |             ^^^^^^^^^^^^ help: try: `0_u32`
+
+error: `x` is never smaller than `0_u32` and has therefore no effect
+  --> tests/ui/unnecessary_min_or_max.rs:25:13
+   |
+LL |     let _ = x.max(0_u32);
+   |             ^^^^^^^^^^^^ help: try: `x`
+
+error: `i32::MIN` is never greater than `x` and has therefore no effect
+  --> tests/ui/unnecessary_min_or_max.rs:29:13
+   |
+LL |     let _ = i32::MIN.min(x);
+   |             ^^^^^^^^^^^^^^^ help: try: `i32::MIN`
+
+error: `i32::MIN` is never greater than `x` and has therefore no effect
+  --> tests/ui/unnecessary_min_or_max.rs:30:13
+   |
+LL |     let _ = i32::MIN.max(x);
+   |             ^^^^^^^^^^^^^^^ help: try: `x`
+
+error: `x` is never smaller than `i32::MIN` and has therefore no effect
+  --> tests/ui/unnecessary_min_or_max.rs:31:13
+   |
+LL |     let _ = x.min(i32::MIN);
+   |             ^^^^^^^^^^^^^^^ help: try: `i32::MIN`
+
+error: `x` is never smaller than `i32::MIN` and has therefore no effect
+  --> tests/ui/unnecessary_min_or_max.rs:32:13
+   |
+LL |     let _ = x.max(i32::MIN);
+   |             ^^^^^^^^^^^^^^^ help: try: `x`
+
+error: `x` is never smaller than `i32::MIN - 0` and has therefore no effect
+  --> tests/ui/unnecessary_min_or_max.rs:34:13
+   |
+LL |     let _ = x.min(i32::MIN - 0);
+   |             ^^^^^^^^^^^^^^^^^^^ help: try: `i32::MIN - 0`
+
+error: `x` is never smaller than `i32::MIN` and has therefore no effect
+  --> tests/ui/unnecessary_min_or_max.rs:35:13
+   |
+LL |     let _ = x.max(i32::MIN);
+   |             ^^^^^^^^^^^^^^^ help: try: `x`
+
+error: `x` is never smaller than `i32::MIN - 0` and has therefore no effect
+  --> tests/ui/unnecessary_min_or_max.rs:37:13
+   |
+LL |     let _ = x.min(i32::MIN - 0);
+   |             ^^^^^^^^^^^^^^^^^^^ help: try: `i32::MIN - 0`
+
+error: aborting due to 17 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unsafe_derive_deserialize.rs b/src/tools/clippy/tests/ui/unsafe_derive_deserialize.rs
index 5187e079042..14371bc203b 100644
--- a/src/tools/clippy/tests/ui/unsafe_derive_deserialize.rs
+++ b/src/tools/clippy/tests/ui/unsafe_derive_deserialize.rs
@@ -1,4 +1,3 @@
-#![feature(lint_reasons)]
 #![warn(clippy::unsafe_derive_deserialize)]
 #![allow(unused, clippy::missing_safety_doc)]
 
diff --git a/src/tools/clippy/tests/ui/unsafe_derive_deserialize.stderr b/src/tools/clippy/tests/ui/unsafe_derive_deserialize.stderr
index 06719f23d57..f2d4429f707 100644
--- a/src/tools/clippy/tests/ui/unsafe_derive_deserialize.stderr
+++ b/src/tools/clippy/tests/ui/unsafe_derive_deserialize.stderr
@@ -1,5 +1,5 @@
 error: you are deriving `serde::Deserialize` on a type that has methods using `unsafe`
-  --> tests/ui/unsafe_derive_deserialize.rs:9:10
+  --> tests/ui/unsafe_derive_deserialize.rs:8:10
    |
 LL | #[derive(Deserialize)]
    |          ^^^^^^^^^^^
@@ -10,7 +10,7 @@ LL | #[derive(Deserialize)]
    = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: you are deriving `serde::Deserialize` on a type that has methods using `unsafe`
-  --> tests/ui/unsafe_derive_deserialize.rs:18:10
+  --> tests/ui/unsafe_derive_deserialize.rs:17:10
    |
 LL | #[derive(Deserialize)]
    |          ^^^^^^^^^^^
@@ -19,7 +19,7 @@ LL | #[derive(Deserialize)]
    = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: you are deriving `serde::Deserialize` on a type that has methods using `unsafe`
-  --> tests/ui/unsafe_derive_deserialize.rs:25:10
+  --> tests/ui/unsafe_derive_deserialize.rs:24:10
    |
 LL | #[derive(Deserialize)]
    |          ^^^^^^^^^^^
@@ -28,7 +28,7 @@ LL | #[derive(Deserialize)]
    = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: you are deriving `serde::Deserialize` on a type that has methods using `unsafe`
-  --> tests/ui/unsafe_derive_deserialize.rs:34:10
+  --> tests/ui/unsafe_derive_deserialize.rs:33:10
    |
 LL | #[derive(Deserialize)]
    |          ^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/unused_rounding.fixed b/src/tools/clippy/tests/ui/unused_rounding.fixed
index 02f970f42a4..7af2c8650a3 100644
--- a/src/tools/clippy/tests/ui/unused_rounding.fixed
+++ b/src/tools/clippy/tests/ui/unused_rounding.fixed
@@ -1,3 +1,5 @@
+// FIXME(f16_f128): add tests when math functions are available
+
 #![warn(clippy::unused_rounding)]
 
 fn main() {
diff --git a/src/tools/clippy/tests/ui/unused_rounding.rs b/src/tools/clippy/tests/ui/unused_rounding.rs
index fd14c466f12..1b0b22a9b68 100644
--- a/src/tools/clippy/tests/ui/unused_rounding.rs
+++ b/src/tools/clippy/tests/ui/unused_rounding.rs
@@ -1,3 +1,5 @@
+// FIXME(f16_f128): add tests when math functions are available
+
 #![warn(clippy::unused_rounding)]
 
 fn main() {
diff --git a/src/tools/clippy/tests/ui/unused_rounding.stderr b/src/tools/clippy/tests/ui/unused_rounding.stderr
index 75ad895012b..c5ae2da75f8 100644
--- a/src/tools/clippy/tests/ui/unused_rounding.stderr
+++ b/src/tools/clippy/tests/ui/unused_rounding.stderr
@@ -1,5 +1,5 @@
 error: used the `ceil` method with a whole number float
-  --> tests/ui/unused_rounding.rs:4:13
+  --> tests/ui/unused_rounding.rs:6:13
    |
 LL |     let _ = 1f32.ceil();
    |             ^^^^^^^^^^^ help: remove the `ceil` method call: `1f32`
@@ -8,25 +8,25 @@ LL |     let _ = 1f32.ceil();
    = help: to override `-D warnings` add `#[allow(clippy::unused_rounding)]`
 
 error: used the `floor` method with a whole number float
-  --> tests/ui/unused_rounding.rs:5:13
+  --> tests/ui/unused_rounding.rs:7:13
    |
 LL |     let _ = 1.0f64.floor();
    |             ^^^^^^^^^^^^^^ help: remove the `floor` method call: `1.0f64`
 
 error: used the `round` method with a whole number float
-  --> tests/ui/unused_rounding.rs:6:13
+  --> tests/ui/unused_rounding.rs:8:13
    |
 LL |     let _ = 1.00f32.round();
    |             ^^^^^^^^^^^^^^^ help: remove the `round` method call: `1.00f32`
 
 error: used the `round` method with a whole number float
-  --> tests/ui/unused_rounding.rs:12:13
+  --> tests/ui/unused_rounding.rs:14:13
    |
 LL |     let _ = 3.0_f32.round();
    |             ^^^^^^^^^^^^^^^ help: remove the `round` method call: `3.0_f32`
 
 error: used the `round` method with a whole number float
-  --> tests/ui/unused_rounding.rs:14:13
+  --> tests/ui/unused_rounding.rs:16:13
    |
 LL |     let _ = 3_3.0_0_f32.round();
    |             ^^^^^^^^^^^^^^^^^^^ help: remove the `round` method call: `3_3.0_0_f32`
diff --git a/src/tools/clippy/tests/ui/used_underscore_binding.rs b/src/tools/clippy/tests/ui/used_underscore_binding.rs
index a8f404b1400..84dccf28f3b 100644
--- a/src/tools/clippy/tests/ui/used_underscore_binding.rs
+++ b/src/tools/clippy/tests/ui/used_underscore_binding.rs
@@ -1,5 +1,5 @@
 //@aux-build:proc_macro_derive.rs
-#![feature(rustc_private, lint_reasons)]
+#![feature(rustc_private)]
 #![warn(clippy::used_underscore_binding)]
 #![allow(clippy::disallowed_names, clippy::eq_op, clippy::uninlined_format_args)]
 
diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml
index 4d66b728b76..0f0e62670ff 100644
--- a/src/tools/clippy/triagebot.toml
+++ b/src/tools/clippy/triagebot.toml
@@ -22,7 +22,6 @@ contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIB
 users_on_vacation = [
     "matthiaskrgr",
     "giraffate",
-    "Centri3",
 ]
 
 [assign.owners]
@@ -32,10 +31,10 @@ users_on_vacation = [
 "*" = [
     "@Manishearth",
     "@llogiq",
-    "@xFrednet",
     "@Alexendoo",
     "@dswij",
     "@Jarcho",
     "@blyxyas",
     "@y21",
+    "@Centri3",
 ]
diff --git a/src/tools/clippy/util/gh-pages/index.html b/src/tools/clippy/util/gh-pages/index.html
index c88c298d5d7..8de36fc4005 100644
--- a/src/tools/clippy/util/gh-pages/index.html
+++ b/src/tools/clippy/util/gh-pages/index.html
@@ -103,6 +103,7 @@ Otherwise, have a great day =^.^=
         @media (min-width: 405px) {
             #upper-filters {
                 display: flex;
+                flex-wrap: wrap;
             }
         }
 
@@ -404,7 +405,7 @@ Otherwise, have a great day =^.^=
 
             <div class="panel panel-default" ng-show="data">
                 <div class="panel-body row">
-                    <div id="upper-filters" class="col-12 col-md-4">
+                    <div id="upper-filters" class="col-12 col-md-6">
                         <div class="btn-group" filter-dropdown>
                             <button type="button" class="btn btn-default dropdown-toggle">
                                 Lint levels <span class="badge">{{selectedValuesCount(levels)}}</span> <span class="caret"></span>
@@ -496,9 +497,34 @@ Otherwise, have a great day =^.^=
                                 </ul>
                             </div>
                         </div>
-
+                        <div class="btn-group" filter-dropdown>
+                            <button type="button" class="btn btn-default dropdown-toggle">
+                                Applicability <span class="badge">{{selectedValuesCount(applicabilities)}}</span> <span class="caret"></span>
+                            </button>
+                            <ul class="dropdown-menu">
+                                <li class="checkbox">
+                                    <label ng-click="toggleApplicabilities(true)">
+                                        <input type="checkbox" class="invisible" />
+                                        All
+                                    </label>
+                                </li>
+                                <li class="checkbox">
+                                    <label ng-click="toggleApplicabilities(false)">
+                                        <input type="checkbox" class="invisible" />
+                                        None
+                                    </label>
+                                </li>
+                                <li role="separator" class="divider"></li>
+                                <li class="checkbox" ng-repeat="(applicability, enabled) in applicabilities">
+                                    <label class="text-capitalize">
+                                        <input type="checkbox" ng-model="applicabilities[applicability]" />
+                                        {{applicability}}
+                                    </label>
+                                </li>
+                            </ul>
+                        </div>
                     </div>
-                    <div class="col-12 col-md-7 search-control">
+                    <div class="col-12 col-md-6 search-control">
                         <div class="input-group">
                             <label class="input-group-addon" id="filter-label" for="search-input">Filter:</label>
                             <input type="text" class="form-control filter-input" placeholder="Keywords or search string" id="search-input"
@@ -514,7 +540,7 @@ Otherwise, have a great day =^.^=
                 </div>
             </div>
             <!-- The order of the filters should be from most likely to remove a lint to least likely to improve performance. -->
-            <article class="panel panel-default" id="{{lint.id}}" ng-repeat="lint in data | filter:bySearch | filter:byGroups | filter:byLevels | filter:byVersion">
+            <article class="panel panel-default" id="{{lint.id}}" ng-repeat="lint in data | filter:bySearch | filter:byGroups | filter:byLevels | filter:byVersion | filter:byApplicabilities">
                 <header class="panel-heading" ng-click="open[lint.id] = !open[lint.id]">
                     <h2 class="panel-title">
                         <div class="panel-title-name">
diff --git a/src/tools/clippy/util/gh-pages/script.js b/src/tools/clippy/util/gh-pages/script.js
index 7cca298df8e..921bb0376f6 100644
--- a/src/tools/clippy/util/gh-pages/script.js
+++ b/src/tools/clippy/util/gh-pages/script.js
@@ -156,6 +156,18 @@
                 Object.entries(versionFilterKeyMap).map(([key, value]) => [value, key])
             );
 
+            const APPLICABILITIES_FILTER_DEFAULT = {
+                Unspecified: true,
+                Unresolved: true,
+                MachineApplicable: true,
+                MaybeIncorrect: true,
+                HasPlaceholders: true
+            };
+
+            $scope.applicabilities = {
+                ...APPLICABILITIES_FILTER_DEFAULT
+            }
+
             // loadFromURLParameters retrieves filter settings from the URL parameters and assigns them
             // to corresponding $scope variables.
             function loadFromURLParameters() {
@@ -182,6 +194,7 @@
 
                 handleParameter('levels', $scope.levels, LEVEL_FILTERS_DEFAULT);
                 handleParameter('groups', $scope.groups, GROUPS_FILTER_DEFAULT);
+                handleParameter('applicabilities', $scope.applicabilities, APPLICABILITIES_FILTER_DEFAULT);
 
                 // Handle 'versions' parameter separately because it needs additional processing
                 if (urlParameters.versions) {
@@ -249,6 +262,7 @@
                 updateURLParameter($scope.levels, 'levels', LEVEL_FILTERS_DEFAULT);
                 updateURLParameter($scope.groups, 'groups', GROUPS_FILTER_DEFAULT);
                 updateVersionURLParameter($scope.versionFilters);
+                updateURLParameter($scope.applicabilities, 'applicabilities', APPLICABILITIES_FILTER_DEFAULT);
             }
 
             // Add $watches to automatically update URL parameters when the data changes
@@ -270,6 +284,12 @@
                 }
             }, true);
 
+            $scope.$watch('applicabilities', function (newVal, oldVal) {
+                if (newVal !== oldVal) {
+                    updateURLParameter(newVal, 'applicabilities', APPLICABILITIES_FILTER_DEFAULT)
+                }
+            }, true);
+
             // Watch for changes in the URL path and update the search and lint display
             $scope.$watch(function () { return $location.path(); }, function (newPath) {
                 const searchParameter = newPath.substring(1);
@@ -327,6 +347,15 @@
                 }
             };
 
+            $scope.toggleApplicabilities = function (value) {
+                const applicabilities = $scope.applicabilities;
+                for (const key in applicabilities) {
+                    if (applicabilities.hasOwnProperty(key)) {
+                        applicabilities[key] = value;
+                    }
+                }
+            }
+
             $scope.resetGroupsToDefault = function () {
                 $scope.groups = {
                     ...GROUPS_FILTER_DEFAULT
@@ -430,6 +459,10 @@
                 return true;
             }
 
+            $scope.byApplicabilities = function (lint) {
+                return $scope.applicabilities[lint.applicability.applicability];
+            };
+
             // Show details for one lint
             $scope.openLint = function (lint) {
                 $scope.open[lint.id] = true;
diff --git a/src/tools/compiletest/src/command-list.rs b/src/tools/compiletest/src/command-list.rs
new file mode 100644
index 00000000000..6735e9faa7a
--- /dev/null
+++ b/src/tools/compiletest/src/command-list.rs
@@ -0,0 +1,232 @@
+/// This was originally generated by collecting directives from ui tests and then extracting their
+/// directive names. This is **not** an exhaustive list of all possible directives. Instead, this is
+/// a best-effort approximation for diagnostics. Add new headers to this list when needed.
+const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
+    // tidy-alphabetical-start
+    "assembly-output",
+    "aux-bin",
+    "aux-build",
+    "aux-codegen-backend",
+    "aux-crate",
+    "build-aux-docs",
+    "build-fail",
+    "build-pass",
+    "check-fail",
+    "check-pass",
+    "check-run-results",
+    "check-stdout",
+    "check-test-line-numbers-match",
+    "compare-output-lines-by-subset",
+    "compile-flags",
+    "dont-check-compiler-stderr",
+    "dont-check-compiler-stdout",
+    "dont-check-failure-status",
+    "edition",
+    "error-pattern",
+    "exec-env",
+    "failure-status",
+    "filecheck-flags",
+    "forbid-output",
+    "force-host",
+    "ignore-16bit",
+    "ignore-32bit",
+    "ignore-64bit",
+    "ignore-aarch64",
+    "ignore-aarch64-unknown-linux-gnu",
+    "ignore-android",
+    "ignore-apple",
+    "ignore-arm",
+    "ignore-avr",
+    "ignore-beta",
+    "ignore-cdb",
+    "ignore-compare-mode-next-solver",
+    "ignore-compare-mode-polonius",
+    "ignore-cross-compile",
+    "ignore-debug",
+    "ignore-eabi",
+    "ignore-emscripten",
+    "ignore-endian-big",
+    "ignore-freebsd",
+    "ignore-fuchsia",
+    "ignore-gdb",
+    "ignore-gdb-version",
+    "ignore-gnu",
+    "ignore-haiku",
+    "ignore-horizon",
+    "ignore-i686-pc-windows-gnu",
+    "ignore-i686-pc-windows-msvc",
+    "ignore-illumos",
+    "ignore-ios",
+    "ignore-linux",
+    "ignore-lldb",
+    "ignore-llvm-version",
+    "ignore-loongarch64",
+    "ignore-macabi",
+    "ignore-macos",
+    "ignore-mode-assembly",
+    "ignore-mode-codegen",
+    "ignore-mode-codegen-units",
+    "ignore-mode-coverage-map",
+    "ignore-mode-coverage-run",
+    "ignore-mode-crashes",
+    "ignore-mode-debuginfo",
+    "ignore-mode-incremental",
+    "ignore-mode-js-doc-test",
+    "ignore-mode-mir-opt",
+    "ignore-mode-pretty",
+    "ignore-mode-run-make",
+    "ignore-mode-run-pass-valgrind",
+    "ignore-mode-rustdoc",
+    "ignore-mode-rustdoc-json",
+    "ignore-mode-ui",
+    "ignore-mode-ui-fulldeps",
+    "ignore-msp430",
+    "ignore-msvc",
+    "ignore-musl",
+    "ignore-netbsd",
+    "ignore-nightly",
+    "ignore-none",
+    "ignore-nto",
+    "ignore-nvptx64",
+    "ignore-nvptx64-nvidia-cuda",
+    "ignore-openbsd",
+    "ignore-pass",
+    "ignore-remote",
+    "ignore-riscv64",
+    "ignore-s390x",
+    "ignore-sgx",
+    "ignore-spirv",
+    "ignore-stable",
+    "ignore-stage1",
+    "ignore-stage2",
+    "ignore-test",
+    "ignore-thumb",
+    "ignore-thumbv8m.base-none-eabi",
+    "ignore-thumbv8m.main-none-eabi",
+    "ignore-tvos",
+    "ignore-unix",
+    "ignore-unknown",
+    "ignore-uwp",
+    "ignore-visionos",
+    "ignore-vxworks",
+    "ignore-wasi",
+    "ignore-wasm",
+    "ignore-wasm32",
+    "ignore-wasm32-bare",
+    "ignore-wasm64",
+    "ignore-watchos",
+    "ignore-windows",
+    "ignore-windows-gnu",
+    "ignore-x32",
+    "ignore-x86",
+    "ignore-x86_64",
+    "ignore-x86_64-apple-darwin",
+    "ignore-x86_64-unknown-linux-gnu",
+    "incremental",
+    "known-bug",
+    "llvm-cov-flags",
+    "min-cdb-version",
+    "min-gdb-version",
+    "min-lldb-version",
+    "min-llvm-version",
+    "min-system-llvm-version",
+    "needs-asm-support",
+    "needs-dlltool",
+    "needs-dynamic-linking",
+    "needs-force-clang-based-tests",
+    "needs-git-hash",
+    "needs-llvm-components",
+    "needs-profiler-support",
+    "needs-relocation-model-pic",
+    "needs-run-enabled",
+    "needs-rust-lld",
+    "needs-rust-lldb",
+    "needs-sanitizer-address",
+    "needs-sanitizer-cfi",
+    "needs-sanitizer-dataflow",
+    "needs-sanitizer-hwaddress",
+    "needs-sanitizer-kcfi",
+    "needs-sanitizer-leak",
+    "needs-sanitizer-memory",
+    "needs-sanitizer-memtag",
+    "needs-sanitizer-safestack",
+    "needs-sanitizer-shadow-call-stack",
+    "needs-sanitizer-support",
+    "needs-sanitizer-thread",
+    "needs-symlink",
+    "needs-threads",
+    "needs-unwind",
+    "needs-wasmtime",
+    "needs-xray",
+    "no-auto-check-cfg",
+    "no-prefer-dynamic",
+    "normalize-stderr-32bit",
+    "normalize-stderr-64bit",
+    "normalize-stderr-test",
+    "normalize-stdout-test",
+    "only-16bit",
+    "only-32bit",
+    "only-64bit",
+    "only-aarch64",
+    "only-apple",
+    "only-arm",
+    "only-avr",
+    "only-beta",
+    "only-bpf",
+    "only-cdb",
+    "only-gnu",
+    "only-i686-pc-windows-gnu",
+    "only-i686-pc-windows-msvc",
+    "only-ios",
+    "only-linux",
+    "only-loongarch64",
+    "only-loongarch64-unknown-linux-gnu",
+    "only-macos",
+    "only-mips",
+    "only-mips64",
+    "only-msp430",
+    "only-msvc",
+    "only-nightly",
+    "only-nvptx64",
+    "only-riscv64",
+    "only-sparc",
+    "only-sparc64",
+    "only-stable",
+    "only-thumb",
+    "only-tvos",
+    "only-unix",
+    "only-visionos",
+    "only-wasm32",
+    "only-wasm32-bare",
+    "only-wasm32-wasip1",
+    "only-watchos",
+    "only-windows",
+    "only-x86",
+    "only-x86_64",
+    "only-x86_64-fortanix-unknown-sgx",
+    "only-x86_64-pc-windows-gnu",
+    "only-x86_64-pc-windows-msvc",
+    "only-x86_64-unknown-linux-gnu",
+    "pp-exact",
+    "pretty-compare-only",
+    "pretty-expanded",
+    "pretty-mode",
+    "regex-error-pattern",
+    "remap-src-base",
+    "revisions",
+    "run-fail",
+    "run-flags",
+    "run-pass",
+    "run-rustfix",
+    "rustc-env",
+    "rustfix-only-machine-applicable",
+    "should-fail",
+    "should-ice",
+    "stderr-per-bitwidth",
+    "test-mir-pass",
+    "unset-exec-env",
+    "unset-rustc-env",
+    // Used by the tidy check `unknown_revision`.
+    "unused-revision-names",
+    // tidy-alphabetical-end
+];
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 5469b9f1a0a..7479be90797 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -723,232 +723,28 @@ pub fn line_directive<'line>(
     }
 }
 
-/// This was originally generated by collecting directives from ui tests and then extracting their
-/// directive names. This is **not** an exhaustive list of all possible directives. Instead, this is
-/// a best-effort approximation for diagnostics. Add new headers to this list when needed.
-const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
-    // tidy-alphabetical-start
-    "assembly-output",
-    "aux-bin",
-    "aux-build",
-    "aux-codegen-backend",
-    "aux-crate",
-    "build-aux-docs",
-    "build-fail",
-    "build-pass",
-    "check-fail",
-    "check-pass",
-    "check-run-results",
-    "check-stdout",
-    "check-test-line-numbers-match",
-    "compare-output-lines-by-subset",
-    "compile-flags",
-    "dont-check-compiler-stderr",
-    "dont-check-compiler-stdout",
-    "dont-check-failure-status",
-    "edition",
-    "error-pattern",
-    "exec-env",
-    "failure-status",
-    "filecheck-flags",
-    "forbid-output",
-    "force-host",
-    "ignore-16bit",
-    "ignore-32bit",
-    "ignore-64bit",
-    "ignore-aarch64",
-    "ignore-aarch64-unknown-linux-gnu",
-    "ignore-android",
-    "ignore-apple",
-    "ignore-arm",
-    "ignore-avr",
-    "ignore-beta",
-    "ignore-cdb",
-    "ignore-compare-mode-next-solver",
-    "ignore-compare-mode-polonius",
-    "ignore-cross-compile",
-    "ignore-debug",
-    "ignore-eabi",
-    "ignore-emscripten",
-    "ignore-endian-big",
-    "ignore-freebsd",
-    "ignore-fuchsia",
-    "ignore-gdb",
-    "ignore-gdb-version",
-    "ignore-gnu",
-    "ignore-haiku",
-    "ignore-horizon",
-    "ignore-i686-pc-windows-msvc",
-    "ignore-ios",
-    "ignore-linux",
-    "ignore-lldb",
-    "ignore-llvm-version",
-    "ignore-loongarch64",
-    "ignore-macabi",
-    "ignore-macos",
-    "ignore-mode-assembly",
-    "ignore-mode-codegen",
-    "ignore-mode-codegen-units",
-    "ignore-mode-coverage-map",
-    "ignore-mode-coverage-run",
-    "ignore-mode-crashes",
-    "ignore-mode-debuginfo",
-    "ignore-mode-incremental",
-    "ignore-mode-js-doc-test",
-    "ignore-mode-mir-opt",
-    "ignore-mode-pretty",
-    "ignore-mode-run-make",
-    "ignore-mode-run-pass-valgrind",
-    "ignore-mode-rustdoc",
-    "ignore-mode-rustdoc-json",
-    "ignore-mode-ui",
-    "ignore-mode-ui-fulldeps",
-    "ignore-msp430",
-    "ignore-msvc",
-    "ignore-musl",
-    "ignore-netbsd",
-    "ignore-nightly",
-    "ignore-none",
-    "ignore-nto",
-    "ignore-nvptx64",
-    "ignore-nvptx64-nvidia-cuda",
-    "ignore-openbsd",
-    "ignore-pass",
-    "ignore-remote",
-    "ignore-riscv64",
-    "ignore-s390x",
-    "ignore-sgx",
-    "ignore-spirv",
-    "ignore-stable",
-    "ignore-stage1",
-    "ignore-stage2",
-    "ignore-test",
-    "ignore-thumb",
-    "ignore-thumbv8m.base-none-eabi",
-    "ignore-thumbv8m.main-none-eabi",
-    "ignore-tvos",
-    "ignore-unix",
-    "ignore-unknown",
-    "ignore-uwp",
-    "ignore-visionos",
-    "ignore-vxworks",
-    "ignore-wasi",
-    "ignore-wasm",
-    "ignore-wasm32",
-    "ignore-wasm32-bare",
-    "ignore-wasm64",
-    "ignore-watchos",
-    "ignore-windows",
-    "ignore-windows-gnu",
-    "ignore-x32",
-    "ignore-x86",
-    "ignore-x86_64",
-    "ignore-x86_64-unknown-linux-gnu",
-    "incremental",
-    "known-bug",
-    "llvm-cov-flags",
-    "min-cdb-version",
-    "min-gdb-version",
-    "min-lldb-version",
-    "min-llvm-version",
-    "min-system-llvm-version",
-    "needs-asm-support",
-    "needs-dlltool",
-    "needs-dynamic-linking",
-    "needs-force-clang-based-tests",
-    "needs-git-hash",
-    "needs-llvm-components",
-    "needs-profiler-support",
-    "needs-relocation-model-pic",
-    "needs-run-enabled",
-    "needs-rust-lld",
-    "needs-rust-lldb",
-    "needs-sanitizer-address",
-    "needs-sanitizer-cfi",
-    "needs-sanitizer-dataflow",
-    "needs-sanitizer-hwaddress",
-    "needs-sanitizer-kcfi",
-    "needs-sanitizer-leak",
-    "needs-sanitizer-memory",
-    "needs-sanitizer-memtag",
-    "needs-sanitizer-safestack",
-    "needs-sanitizer-shadow-call-stack",
-    "needs-sanitizer-support",
-    "needs-sanitizer-thread",
-    "needs-threads",
-    "needs-unwind",
-    "needs-wasmtime",
-    "needs-xray",
-    "no-auto-check-cfg",
-    "no-prefer-dynamic",
-    "normalize-stderr-32bit",
-    "normalize-stderr-64bit",
-    "normalize-stderr-test",
-    "normalize-stdout-test",
-    "only-16bit",
-    "only-32bit",
-    "only-64bit",
-    "only-aarch64",
-    "only-apple",
-    "only-arm",
-    "only-avr",
-    "only-beta",
-    "only-bpf",
-    "only-cdb",
-    "only-gnu",
-    "only-i686-pc-windows-msvc",
-    "only-ios",
-    "only-linux",
-    "only-loongarch64",
-    "only-loongarch64-unknown-linux-gnu",
-    "only-macos",
-    "only-mips",
-    "only-mips64",
-    "only-msp430",
-    "only-msvc",
-    "only-nightly",
-    "only-nvptx64",
-    "only-riscv64",
-    "only-sparc",
-    "only-sparc64",
-    "only-stable",
-    "only-thumb",
-    "only-tvos",
-    "only-unix",
-    "only-visionos",
-    "only-wasm32",
-    "only-wasm32-bare",
-    "only-wasm32-wasip1",
-    "only-watchos",
-    "only-windows",
-    "only-x86",
-    "only-x86_64",
-    "only-x86_64-fortanix-unknown-sgx",
-    "only-x86_64-pc-windows-gnu",
-    "only-x86_64-pc-windows-msvc",
-    "only-x86_64-unknown-linux-gnu",
-    "pp-exact",
-    "pretty-compare-only",
-    "pretty-expanded",
-    "pretty-mode",
-    "regex-error-pattern",
-    "remap-src-base",
-    "revisions",
-    "run-fail",
-    "run-flags",
-    "run-pass",
-    "run-rustfix",
-    "rustc-env",
-    "rustfix-only-machine-applicable",
-    "should-fail",
-    "should-ice",
-    "stderr-per-bitwidth",
-    "test-mir-pass",
-    "unset-exec-env",
-    "unset-rustc-env",
-    // Used by the tidy check `unknown_revision`.
-    "unused-revision-names",
-    // tidy-alphabetical-end
+// To prevent duplicating the list of commmands between `compiletest` and `htmldocck`, we put
+// it into a common file which is included in rust code and parsed here.
+// FIXME: This setup is temporary until we figure out how to improve this situation.
+include!("command-list.rs");
+
+const KNOWN_RUSTDOC_DIRECTIVE_NAMES: &[&str] = &[
+    "count",
+    "!count",
+    "files",
+    "!files",
+    "has",
+    "!has",
+    "has-dir",
+    "!has-dir",
+    "hasraw",
+    "!hasraw",
+    "matches",
+    "!matches",
+    "matchesraw",
+    "!matchesraw",
+    "snapshot",
+    "!snapshot",
 ];
 
 /// The broken-down contents of a line containing a test header directive,
@@ -985,20 +781,30 @@ pub(crate) struct CheckDirectiveResult<'ln> {
     trailing_directive: Option<&'ln str>,
 }
 
-pub(crate) fn check_directive(directive_ln: &str) -> CheckDirectiveResult<'_> {
+pub(crate) fn check_directive<'a>(
+    directive_ln: &'a str,
+    is_rustdoc: bool,
+    original_line: &str,
+) -> CheckDirectiveResult<'a> {
     let (directive_name, post) = directive_ln.split_once([':', ' ']).unwrap_or((directive_ln, ""));
 
     let trailing = post.trim().split_once(' ').map(|(pre, _)| pre).unwrap_or(post);
+    let is_known = |s: &str| {
+        KNOWN_DIRECTIVE_NAMES.contains(&s)
+            || (is_rustdoc
+                && original_line.starts_with("//@")
+                && KNOWN_RUSTDOC_DIRECTIVE_NAMES.contains(&s))
+    };
     let trailing_directive = {
         // 1. is the directive name followed by a space? (to exclude `:`)
         matches!(directive_ln.get(directive_name.len()..), Some(s) if s.starts_with(' '))
             // 2. is what is after that directive also a directive (ex: "only-x86 only-arm")
-            && KNOWN_DIRECTIVE_NAMES.contains(&trailing)
+            && is_known(trailing)
     }
     .then_some(trailing);
 
     CheckDirectiveResult {
-        is_known_directive: KNOWN_DIRECTIVE_NAMES.contains(&directive_name),
+        is_known_directive: is_known(&directive_name),
         directive_name: directive_ln,
         trailing_directive,
     }
@@ -1069,7 +875,7 @@ fn iter_header(
                 let directive_ln = non_revisioned_directive_line.trim();
 
                 let CheckDirectiveResult { is_known_directive, trailing_directive, .. } =
-                    check_directive(directive_ln);
+                    check_directive(directive_ln, mode == Mode::Rustdoc, ln);
 
                 if !is_known_directive {
                     *poisoned = true;
@@ -1122,7 +928,7 @@ fn iter_header(
             let rest = rest.trim_start();
 
             let CheckDirectiveResult { is_known_directive, directive_name, .. } =
-                check_directive(rest);
+                check_directive(rest, mode == Mode::Rustdoc, ln);
 
             if is_known_directive {
                 *poisoned = true;
@@ -1315,13 +1121,11 @@ fn expand_variables(mut value: String, config: &Config) -> String {
 /// normalize-*: "REGEX" -> "REPLACEMENT"
 /// ```
 fn parse_normalize_rule(header: &str) -> Option<(String, String)> {
-    // FIXME(#126370): A colon after the header name should be mandatory, but
-    // currently is not, and there are many tests that lack the colon.
     // FIXME: Support escaped double-quotes in strings.
     let captures = static_regex!(
         r#"(?x) # (verbose mode regex)
         ^
-        [^:\s]+:?\s*            # (header name followed by optional colon)
+        [^:\s]+:\s*             # (header name followed by colon)
         "(?<regex>[^"]*)"       # "REGEX"
         \s+->\s+                # ->
         "(?<replacement>[^"]*)" # "REPLACEMENT"
diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs
index b96832db67b..5b2665f7d0b 100644
--- a/src/tools/compiletest/src/header/needs.rs
+++ b/src/tools/compiletest/src/header/needs.rs
@@ -144,6 +144,11 @@ pub(super) fn handle_needs(
             condition: config.runner.as_ref().is_some_and(|r| r.contains("wasmtime")),
             ignore_reason: "ignored when wasmtime runner is not available",
         },
+        Need {
+            name: "needs-symlink",
+            condition: cache.symlinks,
+            ignore_reason: "ignored if symlinks are unavailable",
+        },
     ];
 
     let (name, comment) = match ln.split_once([':', ' ']) {
@@ -209,6 +214,7 @@ pub(super) struct CachedNeedsConditions {
     xray: bool,
     rust_lld: bool,
     dlltool: bool,
+    symlinks: bool,
 }
 
 impl CachedNeedsConditions {
@@ -253,6 +259,7 @@ impl CachedNeedsConditions {
                 .exists(),
 
             dlltool: find_dlltool(&config),
+            symlinks: has_symlinks(),
         }
     }
 }
@@ -279,3 +286,22 @@ fn find_dlltool(config: &Config) -> bool {
     };
     dlltool_found
 }
+
+#[cfg(windows)]
+fn has_symlinks() -> bool {
+    if std::env::var_os("CI").is_some() {
+        return true;
+    }
+    let link = std::env::temp_dir().join("RUST_COMPILETEST_SYMLINK_CHECK");
+    if std::os::windows::fs::symlink_file("DOES NOT EXIST", &link).is_ok() {
+        std::fs::remove_file(&link).unwrap();
+        true
+    } else {
+        false
+    }
+}
+
+#[cfg(not(windows))]
+fn has_symlinks() -> bool {
+    true
+}
diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs
index 61a85b84ad6..c790eb18d67 100644
--- a/src/tools/compiletest/src/header/tests.rs
+++ b/src/tools/compiletest/src/header/tests.rs
@@ -33,20 +33,11 @@ fn make_test_description<R: Read>(
 
 #[test]
 fn test_parse_normalize_rule() {
-    let good_data = &[
-        (
-            r#"normalize-stderr-32bit: "something (32 bits)" -> "something ($WORD bits)""#,
-            "something (32 bits)",
-            "something ($WORD bits)",
-        ),
-        // FIXME(#126370): A colon after the header name should be mandatory,
-        // but currently is not, and there are many tests that lack the colon.
-        (
-            r#"normalize-stderr-32bit "something (32 bits)" -> "something ($WORD bits)""#,
-            "something (32 bits)",
-            "something ($WORD bits)",
-        ),
-    ];
+    let good_data = &[(
+        r#"normalize-stderr-32bit: "something (32 bits)" -> "something ($WORD bits)""#,
+        "something (32 bits)",
+        "something ($WORD bits)",
+    )];
 
     for &(input, expected_regex, expected_replacement) in good_data {
         let parsed = parse_normalize_rule(input);
@@ -56,6 +47,7 @@ fn test_parse_normalize_rule() {
     }
 
     let bad_data = &[
+        r#"normalize-stderr-32bit "something (32 bits)" -> "something ($WORD bits)""#,
         r#"normalize-stderr-16bit: something (16 bits) -> something ($WORD bits)"#,
         r#"normalize-stderr-32bit: something (32 bits) -> something ($WORD bits)"#,
         r#"normalize-stderr-32bit: "something (32 bits) -> something ($WORD bits)"#,
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 72b57d91c23..1a4101e4de8 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -374,11 +374,12 @@ impl<'test> TestCx<'test> {
 
         // if a test does not crash, consider it an error
         if proc_res.status.success() || matches!(proc_res.status.code(), Some(1 | 0)) {
-            self.fatal(
-                "test no longer crashes/triggers ICE! Please give it a mearningful name, \
+            self.fatal(&format!(
+                "crashtest no longer crashes/triggers ICE, horray! Please give it a meaningful name, \
             add a doc-comment to the start of the test explaining why it exists and \
-            move it to tests/ui or wherever you see fit.",
-            );
+            move it to tests/ui or wherever you see fit. Adding 'Fixes #<issueNr>' to your PR description \
+            ensures that the corresponding ticket is auto-closed upon merge."
+            ));
         }
     }
 
diff --git a/src/tools/generate-windows-sys/Cargo.toml b/src/tools/generate-windows-sys/Cargo.toml
index ebf3082fb4f..882d3d63525 100644
--- a/src/tools/generate-windows-sys/Cargo.toml
+++ b/src/tools/generate-windows-sys/Cargo.toml
@@ -4,4 +4,4 @@ version = "0.1.0"
 edition = "2021"
 
 [dependencies.windows-bindgen]
-version = "0.57.0"
+version = "0.58.0"
diff --git a/src/tools/generate-windows-sys/src/main.rs b/src/tools/generate-windows-sys/src/main.rs
index c8913910bd6..fd21e7a86b0 100644
--- a/src/tools/generate-windows-sys/src/main.rs
+++ b/src/tools/generate-windows-sys/src/main.rs
@@ -17,6 +17,7 @@ fn main() -> Result<(), Box<dyn Error>> {
 
     let mut f = std::fs::File::options().append(true).open("windows_sys.rs")?;
     writeln!(&mut f, "// ignore-tidy-filelength")?;
+    writeln!(&mut f, "use super::windows_targets;")?;
 
     Ok(())
 }
diff --git a/src/tools/jsondocck/src/cache.rs b/src/tools/jsondocck/src/cache.rs
index 50697d46b8c..5f72bd171a1 100644
--- a/src/tools/jsondocck/src/cache.rs
+++ b/src/tools/jsondocck/src/cache.rs
@@ -23,7 +23,7 @@ impl Cache {
 
         Cache {
             value: serde_json::from_str::<Value>(&content).expect("failed to convert from JSON"),
-            variables: HashMap::new(),
+            variables: HashMap::from([("FILE".to_owned(), config.template.clone().into())]),
         }
     }
 
diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs
index 688b403bf0e..429c6151796 100644
--- a/src/tools/jsondocck/src/main.rs
+++ b/src/tools/jsondocck/src/main.rs
@@ -56,6 +56,8 @@ pub enum CommandKind {
 
 impl CommandKind {
     fn validate(&self, args: &[String], lineno: usize) -> bool {
+        // FIXME(adotinthevoid): We should "parse, don't validate" here, so we avoid ad-hoc
+        // indexing in check_command.
         let count = match self {
             CommandKind::Has => (1..=2).contains(&args.len()),
             CommandKind::IsMany => args.len() >= 2,
@@ -71,7 +73,7 @@ impl CommandKind {
         if let CommandKind::Count = self {
             if args[1].parse::<usize>().is_err() {
                 print_err(
-                    &format!("Second argument to @count must be a valid usize (got `{}`)", args[2]),
+                    &format!("Second argument to @count must be a valid usize (got `{}`)", args[1]),
                     lineno,
                 );
                 return false;
diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs
index 1713a4d812c..cd011dce784 100644
--- a/src/tools/jsondoclint/src/validator.rs
+++ b/src/tools/jsondoclint/src/validator.rs
@@ -374,8 +374,8 @@ impl<'a> Validator<'a> {
                 bounds.iter().for_each(|b| self.check_generic_bound(b));
                 generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd));
             }
-            WherePredicate::RegionPredicate { lifetime: _, bounds } => {
-                bounds.iter().for_each(|b| self.check_generic_bound(b));
+            WherePredicate::LifetimePredicate { lifetime: _, outlives: _ } => {
+                // nop, all strings.
             }
             WherePredicate::EqPredicate { lhs, rhs } => {
                 self.check_type(lhs);
diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs
index 7321bd1bb52..72ae3ed26e8 100644
--- a/src/tools/linkchecker/main.rs
+++ b/src/tools/linkchecker/main.rs
@@ -59,6 +59,8 @@ const INTRA_DOC_LINK_EXCEPTIONS: &[(&str, &[&str])] = &[
     // This is being used in the sense of 'inclusive range', not a markdown link
     ("core/ops/struct.RangeInclusive.html", &["begin</code>, <code>end"]),
     ("std/ops/struct.RangeInclusive.html", &["begin</code>, <code>end"]),
+    ("core/range/legacy/struct.RangeInclusive.html", &["begin</code>, <code>end"]),
+    ("std/range/legacy/struct.RangeInclusive.html", &["begin</code>, <code>end"]),
     ("core/slice/trait.SliceIndex.html", &["begin</code>, <code>end"]),
     ("alloc/slice/trait.SliceIndex.html", &["begin</code>, <code>end"]),
     ("std/slice/trait.SliceIndex.html", &["begin</code>, <code>end"]),
diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml
index 3bc4163ab52..fc4e484fa38 100644
--- a/src/tools/miri/.github/workflows/ci.yml
+++ b/src/tools/miri/.github/workflows/ci.yml
@@ -33,50 +33,7 @@ jobs:
       HOST_TARGET: ${{ matrix.host_target }}
     steps:
       - uses: actions/checkout@v4
-
-      - name: Show Rust version (stable toolchain)
-        run: |
-          rustup show
-          rustc -Vv
-          cargo -V
-
-      # Cache the global cargo directory, but NOT the local `target` directory which
-      # we cannot reuse anyway when the nightly changes (and it grows quite large
-      # over time).
-      - name: Add cache for cargo
-        id: cache
-        uses: actions/cache@v4
-        with:
-          path: |
-            # Taken from <https://doc.rust-lang.org/nightly/cargo/guide/cargo-home.html#caching-the-cargo-home-in-ci>.
-            # Cache package/registry information
-            ~/.cargo/registry/index
-            ~/.cargo/registry/cache
-            ~/.cargo/git/db
-            # Cache installed binaries
-            ~/.cargo/bin
-            ~/.cargo/.crates.toml
-            ~/.cargo/.crates2.json
-          key: cargo-${{ runner.os }}-reset20240425-${{ hashFiles('**/Cargo.lock') }}
-          restore-keys: cargo-${{ runner.os }}-reset20240425
-
-      - name: Install tools
-        if: steps.cache.outputs.cache-hit != 'true'
-        run: cargo install -f rustup-toolchain-install-master hyperfine
-
-      - name: Install miri toolchain
-        run: |
-          if [[ ${{ github.event_name }} == 'schedule' ]]; then
-            echo "Building against latest rustc git version"
-            git ls-remote https://github.com/rust-lang/rust/ HEAD | cut -f 1 > rust-version
-          fi
-          ./miri toolchain --host ${{ matrix.host_target }}
-
-      - name: Show Rust version (miri toolchain)
-        run: |
-          rustup show
-          rustc -Vv
-          cargo -V
+      - uses: ./.github/workflows/setup
 
       # The `style` job only runs on Linux; this makes sure the Windows-host-specific
       # code is also covered by clippy.
@@ -92,47 +49,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
-
-      # This is exactly duplicated from above. GHA is pretty terrible when it comes
-      # to avoiding code duplication.
-
-      # Cache the global cargo directory, but NOT the local `target` directory which
-      # we cannot reuse anyway when the nightly changes (and it grows quite large
-      # over time).
-      - name: Add cache for cargo
-        id: cache
-        uses: actions/cache@v4
-        with:
-          path: |
-            # Taken from <https://doc.rust-lang.org/nightly/cargo/guide/cargo-home.html#caching-the-cargo-home-in-ci>.
-            # Cache package/registry information
-            ~/.cargo/registry/index
-            ~/.cargo/registry/cache
-            ~/.cargo/git/db
-            # Cache installed binaries
-            ~/.cargo/bin
-            ~/.cargo/.crates.toml
-            ~/.cargo/.crates2.json
-          key: cargo-${{ runner.os }}-reset20240331-${{ hashFiles('**/Cargo.lock') }}
-          restore-keys: cargo-${{ runner.os }}-reset20240331
-
-      - name: Install rustup-toolchain-install-master
-        if: steps.cache.outputs.cache-hit != 'true'
-        run: cargo install -f rustup-toolchain-install-master
-
-      - name: Install "master" toolchain
-        run: |
-          if [[ ${{ github.event_name }} == 'schedule' ]]; then
-            echo "Building against latest rustc git version"
-            git ls-remote https://github.com/rust-lang/rust/ HEAD | cut -f 1 > rust-version
-          fi
-          ./miri toolchain
-
-      - name: Show Rust version
-        run: |
-          rustup show
-          rustc -Vv
-          cargo -V
+      - uses: ./.github/workflows/setup
 
       - name: rustfmt
         run: ./miri fmt --check
diff --git a/src/tools/miri/.github/workflows/setup/action.yml b/src/tools/miri/.github/workflows/setup/action.yml
new file mode 100644
index 00000000000..8f54b5b8d81
--- /dev/null
+++ b/src/tools/miri/.github/workflows/setup/action.yml
@@ -0,0 +1,52 @@
+name: "Miri CI setup"
+description: "Sets up Miri CI"
+runs:
+  using: "composite"
+  steps:
+      - name: Show Rust version (stable toolchain)
+        run: |
+          rustup show
+          rustc -Vv
+          cargo -V
+        shell: bash
+
+      # Cache the global cargo directory, but NOT the local `target` directory which
+      # we cannot reuse anyway when the nightly changes (and it grows quite large
+      # over time).
+      - name: Add cache for cargo
+        id: cache
+        uses: actions/cache@v4
+        with:
+          path: |
+            # Taken from <https://doc.rust-lang.org/nightly/cargo/guide/cargo-home.html#caching-the-cargo-home-in-ci>.
+            # Cache package/registry information
+            ~/.cargo/registry/index
+            ~/.cargo/registry/cache
+            ~/.cargo/git/db
+            # Cache installed binaries
+            ~/.cargo/bin
+            ~/.cargo/.crates.toml
+            ~/.cargo/.crates2.json
+          key: cargo-${{ runner.os }}-${{ hashFiles('**/Cargo.lock', '.github/workflows/**/*.yml') }}
+          restore-keys: cargo-${{ runner.os }}
+
+      - name: Install rustup-toolchain-install-master
+        if: steps.cache.outputs.cache-hit != 'true'
+        run: cargo install -f rustup-toolchain-install-master hyperfine
+        shell: bash
+
+      - name: Install "master" toolchain
+        run: |
+          if [[ ${{ github.event_name }} == 'schedule' ]]; then
+            echo "Building against latest rustc git version"
+            git ls-remote https://github.com/rust-lang/rust/ HEAD | cut -f 1 > rust-version
+          fi
+          ./miri toolchain
+        shell: bash
+
+      - name: Show Rust version (miri toolchain)
+        run: |
+          rustup show
+          rustc -Vv
+          cargo -V
+        shell: bash
diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md
index 4b4f2f83062..b1be596c006 100644
--- a/src/tools/miri/README.md
+++ b/src/tools/miri/README.md
@@ -72,11 +72,13 @@ Further caveats that Miri users should be aware of:
   when `SeqCst` fences are used that are not actually permitted by the Rust memory model, and it
   cannot produce all behaviors possibly observable on real hardware.
 
-Moreover, Miri fundamentally cannot tell you whether your code is *sound*. [Soundness] is the property
-of never causing undefined behavior when invoked from arbitrary safe code, even in combination with
+Moreover, Miri fundamentally cannot ensure that your code is *sound*. [Soundness] is the property of
+never causing undefined behavior when invoked from arbitrary safe code, even in combination with
 other sound code. In contrast, Miri can just tell you if *a particular way of interacting with your
-code* (e.g., a test suite) causes any undefined behavior. It is up to you to ensure sufficient
-coverage.
+code* (e.g., a test suite) causes any undefined behavior *in a particular execution* (of which there
+may be many, e.g. when concurrency or other forms of non-determinism are involved). When Miri finds
+UB, your code is definitely unsound, but when Miri does not find UB, then you may just have to test
+more inputs or more possible non-deterministic choices.
 
 [rust]: https://www.rust-lang.org/
 [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md
@@ -425,8 +427,12 @@ to Miri failing to detect cases of undefined behavior in a program.
   value from a load. This can help diagnose problems that disappear under
   `-Zmiri-disable-weak-memory-emulation`.
 * `-Zmiri-tree-borrows` replaces [Stacked Borrows] with the [Tree Borrows] rules.
-  The soundness rules are already experimental without this flag, but even more
-  so with this flag.
+  Tree Borrows is even more experimental than Stacked Borrows. While Tree Borrows
+  is still sound in the sense of catching all aliasing violations that current versions
+  of the compiler might exploit, it is likely that the eventual final aliasing model
+  of Rust will be stricter than Tree Borrows. In other words, if you use Tree Borrows,
+  even if your code is accepted today, it might be declared UB in the future.
+  This is much less likely with Stacked Borrows.
 * `-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
diff --git a/src/tools/miri/build.rs b/src/tools/miri/build.rs
index 0977c0ba016..0918c9b1321 100644
--- a/src/tools/miri/build.rs
+++ b/src/tools/miri/build.rs
@@ -1,8 +1,10 @@
 fn main() {
     // Don't rebuild miri when nothing changed.
     println!("cargo:rerun-if-changed=build.rs");
-    // Re-export the TARGET environment variable so it can
-    // be accessed by miri.
+    // Re-export the TARGET environment variable so it can be accessed by miri. Needed to know the
+    // "host" triple inside Miri.
     let target = std::env::var("TARGET").unwrap();
     println!("cargo:rustc-env=TARGET={target}");
+    // Allow some cfgs.
+    println!("cargo::rustc-check-cfg=cfg(bootstrap)");
 }
diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs
index 3c36f606d84..8d48b9c8ad1 100644
--- a/src/tools/miri/cargo-miri/src/phases.rs
+++ b/src/tools/miri/cargo-miri/src/phases.rs
@@ -23,6 +23,12 @@ Subcommands:
     clean                    Clean the Miri cache & target directory
 
 The cargo options are exactly the same as for `cargo run` and `cargo test`, respectively.
+Furthermore, the following extra flags and environment variables are recognized for `run` and `test`:
+
+    --many-seeds[=from..to]  Run the program/tests many times with different seeds in the given range.
+                             The range defaults to `0..64`.
+
+    MIRIFLAGS                Extra flags to pass to the Miri driver. Use this to pass `-Zmiri-...` flags.
 
 Examples:
     cargo miri run
diff --git a/src/tools/miri/miri b/src/tools/miri/miri
index 5f71fc94438..07383bb59eb 100755
--- a/src/tools/miri/miri
+++ b/src/tools/miri/miri
@@ -3,5 +3,6 @@ set -e
 # Instead of doing just `cargo run --manifest-path .. $@`, we invoke miri-script binary directly. Invoking `cargo run` goes through
 # rustup (that sets it's own environmental variables), which is undesirable.
 MIRI_SCRIPT_TARGET_DIR="$(dirname "$0")"/miri-script/target
-cargo +stable build $CARGO_EXTRA_FLAGS -q --target-dir "$MIRI_SCRIPT_TARGET_DIR" --manifest-path "$(dirname "$0")"/miri-script/Cargo.toml
+cargo +stable build $CARGO_EXTRA_FLAGS -q --target-dir "$MIRI_SCRIPT_TARGET_DIR" --manifest-path "$(dirname "$0")"/miri-script/Cargo.toml || \
+  ( echo "Failed to build miri-script. Is the 'stable' toolchain installed?"; exit 1 )
 "$MIRI_SCRIPT_TARGET_DIR"/debug/miri-script "$@"
diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs
index 57bdfbad9af..62a3ab2c34c 100644
--- a/src/tools/miri/miri-script/src/commands.rs
+++ b/src/tools/miri/miri-script/src/commands.rs
@@ -252,12 +252,11 @@ impl Command {
         // Fetch given rustc commit.
         cmd!(sh, "git fetch http://localhost:{JOSH_PORT}/rust-lang/rust.git@{commit}{JOSH_FILTER}.git")
             .run()
-            .map_err(|e| {
+            .inspect_err(|_| {
                 // Try to un-do the previous `git commit`, to leave the repo in the state we found it.
                 cmd!(sh, "git reset --hard HEAD^")
                     .run()
                     .expect("FAILED to clean up again after failed `git fetch`, sorry for that");
-                e
             })
             .context("FAILED to fetch new commits, something went wrong (committing the rust-version file has been undone)")?;
 
@@ -545,9 +544,8 @@ impl Command {
         if let Some(seed_range) = many_seeds {
             e.run_many_times(seed_range, |sh, seed| {
                 eprintln!("Trying seed: {seed}");
-                run_miri(sh, Some(format!("-Zmiri-seed={seed}"))).map_err(|err| {
+                run_miri(sh, Some(format!("-Zmiri-seed={seed}"))).inspect_err(|_| {
                     eprintln!("FAILING SEED: {seed}");
-                    err
                 })
             })?;
         } else {
diff --git a/src/tools/miri/miri-script/src/util.rs b/src/tools/miri/miri-script/src/util.rs
index e9095a45fce..e1b77be192e 100644
--- a/src/tools/miri/miri-script/src/util.rs
+++ b/src/tools/miri/miri-script/src/util.rs
@@ -219,10 +219,9 @@ impl MiriEnv {
                             break;
                         }
                         // Run the command with this seed.
-                        run(&local_shell, cur).map_err(|err| {
+                        run(&local_shell, cur).inspect_err(|_| {
                             // If we failed, tell everyone about this.
                             failed.store(true, Ordering::Relaxed);
-                            err
                         })?;
                         // Check if some other command failed (in which case we'll stop as well).
                         if failed.load(Ordering::Relaxed) {
diff --git a/src/tools/miri/miri.bat b/src/tools/miri/miri.bat
index 18baa683f65..6f9a8f38d65 100644
--- a/src/tools/miri/miri.bat
+++ b/src/tools/miri/miri.bat
@@ -5,7 +5,8 @@ set MIRI_SCRIPT_TARGET_DIR=%0\..\miri-script\target
 
 :: If any other steps are added, the "|| exit /b" must be appended to early
 :: return from the script. If not, it will continue execution.
-cargo +stable build %CARGO_EXTRA_FLAGS% -q --target-dir %MIRI_SCRIPT_TARGET_DIR% --manifest-path %0\..\miri-script\Cargo.toml || exit /b
+cargo +stable build %CARGO_EXTRA_FLAGS% -q --target-dir %MIRI_SCRIPT_TARGET_DIR% --manifest-path %0\..\miri-script\Cargo.toml ^
+  || (echo Failed to build miri-script. Is the 'stable' toolchain installed? & exit /b)
 
 :: Forwards all arguments to this file to the executable.
 :: We invoke the binary directly to avoid going through rustup, which would set some extra
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index e49680ba75a..5a35166769e 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-f6b4b71ef10307201b52c17b0f9dcf9557cd90ba
+66b4f0021bfb11a8c20d084c99a40f4a78ce1d38
diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs
index ae95d28d3eb..d0f977f8143 100644
--- a/src/tools/miri/src/alloc_addresses/mod.rs
+++ b/src/tools/miri/src/alloc_addresses/mod.rs
@@ -97,7 +97,7 @@ impl GlobalStateInner {
 fn align_addr(addr: u64, align: u64) -> u64 {
     match addr % align {
         0 => addr,
-        rem => addr.checked_add(align).unwrap() - rem,
+        rem => addr.strict_add(align) - rem,
     }
 }
 
diff --git a/src/tools/miri/src/alloc_bytes.rs b/src/tools/miri/src/alloc_bytes.rs
index 97841a05cde..84225d83b6a 100644
--- a/src/tools/miri/src/alloc_bytes.rs
+++ b/src/tools/miri/src/alloc_bytes.rs
@@ -64,17 +64,19 @@ impl MiriAllocBytes {
     /// If `size == 0` we allocate using a different `alloc_layout` with `size = 1`, to ensure each allocation has a unique address.
     /// Returns `Err(alloc_layout)` if the allocation function returns a `ptr` where `ptr.is_null()`.
     fn alloc_with(
-        size: usize,
-        align: usize,
+        size: u64,
+        align: u64,
         alloc_fn: impl FnOnce(Layout) -> *mut u8,
-    ) -> Result<MiriAllocBytes, Layout> {
-        let layout = Layout::from_size_align(size, align).unwrap();
+    ) -> Result<MiriAllocBytes, ()> {
+        let size = usize::try_from(size).map_err(|_| ())?;
+        let align = usize::try_from(align).map_err(|_| ())?;
+        let layout = Layout::from_size_align(size, align).map_err(|_| ())?;
         // When size is 0 we allocate 1 byte anyway, to ensure each allocation has a unique address.
         let alloc_layout =
             if size == 0 { Layout::from_size_align(1, align).unwrap() } else { layout };
         let ptr = alloc_fn(alloc_layout);
         if ptr.is_null() {
-            Err(alloc_layout)
+            Err(())
         } else {
             // SAFETY: All `MiriAllocBytes` invariants are fulfilled.
             Ok(Self { ptr, layout })
@@ -86,11 +88,13 @@ impl AllocBytes for MiriAllocBytes {
     fn from_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, align: Align) -> Self {
         let slice = slice.into();
         let size = slice.len();
-        let align = align.bytes_usize();
+        let align = align.bytes();
         // SAFETY: `alloc_fn` will only be used with `size != 0`.
         let alloc_fn = |layout| unsafe { alloc::alloc(layout) };
-        let alloc_bytes = MiriAllocBytes::alloc_with(size, align, alloc_fn)
-            .unwrap_or_else(|layout| alloc::handle_alloc_error(layout));
+        let alloc_bytes = MiriAllocBytes::alloc_with(size.try_into().unwrap(), align, alloc_fn)
+            .unwrap_or_else(|()| {
+                panic!("Miri ran out of memory: cannot create allocation of {size} bytes")
+            });
         // SAFETY: `alloc_bytes.ptr` and `slice.as_ptr()` are non-null, properly aligned
         // and valid for the `size`-many bytes to be copied.
         unsafe { alloc_bytes.ptr.copy_from(slice.as_ptr(), size) };
@@ -98,8 +102,8 @@ impl AllocBytes for MiriAllocBytes {
     }
 
     fn zeroed(size: Size, align: Align) -> Option<Self> {
-        let size = size.bytes_usize();
-        let align = align.bytes_usize();
+        let size = size.bytes();
+        let align = align.bytes();
         // SAFETY: `alloc_fn` will only be used with `size != 0`.
         let alloc_fn = |layout| unsafe { alloc::alloc_zeroed(layout) };
         MiriAllocBytes::alloc_with(size, align, alloc_fn).ok()
@@ -108,4 +112,8 @@ impl AllocBytes for MiriAllocBytes {
     fn as_mut_ptr(&mut self) -> *mut u8 {
         self.ptr
     }
+
+    fn as_ptr(&self) -> *const u8 {
+        self.ptr
+    }
 }
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 829bfa7cd70..9d8e44ce409 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -98,10 +98,9 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
             }
 
             if tcx.sess.opts.optimize != OptLevel::No {
-                tcx.dcx().warn("Miri does not support optimizations. If you have enabled optimizations \
-                    by selecting a Cargo profile (such as --release) which changes other profile settings \
-                    such as whether debug assertions and overflow checks are enabled, those settings are \
-                    still applied.");
+                tcx.dcx().warn("Miri does not support optimizations: the opt-level is ignored. The only effect \
+                    of selecting a Cargo profile that enables optimizations (such as --release) is to apply \
+                    its remaining settings, such as whether debug assertions and overflow checks are enabled.");
             }
             if tcx.sess.mir_opt_level() > 0 {
                 tcx.dcx().warn("You have explicitly enabled MIR optimizations, overriding Miri's default \
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 8abc8530f7c..a753de28a04 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
@@ -19,7 +19,7 @@ pub enum AccessCause {
     Explicit(AccessKind),
     Reborrow,
     Dealloc,
-    FnExit,
+    FnExit(AccessKind),
 }
 
 impl fmt::Display for AccessCause {
@@ -28,7 +28,11 @@ impl fmt::Display for AccessCause {
             Self::Explicit(kind) => write!(f, "{kind}"),
             Self::Reborrow => write!(f, "reborrow"),
             Self::Dealloc => write!(f, "deallocation"),
-            Self::FnExit => write!(f, "protector release"),
+            // This is dead code, since the protector release access itself can never
+            // cause UB (while the protector is active, if some other access invalidates
+            // further use of the protected tag, that is immediate UB).
+            // Describing the cause of UB is the only time this function is called.
+            Self::FnExit(_) => unreachable!("protector accesses can never be the source of UB"),
         }
     }
 }
@@ -40,7 +44,7 @@ impl AccessCause {
             Self::Explicit(kind) => format!("{rel} {kind}"),
             Self::Reborrow => format!("reborrow (acting as a {rel} read access)"),
             Self::Dealloc => format!("deallocation (acting as a {rel} write access)"),
-            Self::FnExit => format!("protector release (acting as a {rel} read access)"),
+            Self::FnExit(kind) => format!("protector release (acting as a {rel} {kind})"),
         }
     }
 }
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 77e003ab8a7..86074384084 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
@@ -68,13 +68,11 @@ impl<'tcx> Tree {
         let global = machine.borrow_tracker.as_ref().unwrap();
         let span = machine.current_span();
         self.perform_access(
-            access_kind,
             tag,
-            Some(range),
+            Some((range, access_kind, diagnostics::AccessCause::Explicit(access_kind))),
             global,
             alloc_id,
             span,
-            diagnostics::AccessCause::Explicit(access_kind),
         )
     }
 
@@ -115,15 +113,8 @@ impl<'tcx> Tree {
         alloc_id: AllocId, // diagnostics
     ) -> InterpResult<'tcx> {
         let span = machine.current_span();
-        self.perform_access(
-            AccessKind::Read,
-            tag,
-            None, // no specified range because it occurs on the entire allocation
-            global,
-            alloc_id,
-            span,
-            diagnostics::AccessCause::FnExit,
-        )
+        // `None` makes it the magic on-protector-end operation
+        self.perform_access(tag, None, global, alloc_id, span)
     }
 }
 
@@ -297,13 +288,11 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         // All reborrows incur a (possibly zero-sized) read access to the parent
         tree_borrows.perform_access(
-            AccessKind::Read,
             orig_tag,
-            Some(range),
+            Some((range, AccessKind::Read, diagnostics::AccessCause::Reborrow)),
             this.machine.borrow_tracker.as_ref().unwrap(),
             alloc_id,
             this.machine.current_span(),
-            diagnostics::AccessCause::Reborrow,
         )?;
         // Record the parent-child pair in the tree.
         tree_borrows.new_child(orig_tag, new_tag, new_perm.initial_state, range, span)?;
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 fb3a4c8dad9..7aa9c3e862b 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
@@ -186,6 +186,10 @@ impl Permission {
     pub fn is_disabled(&self) -> bool {
         self.inner == Disabled
     }
+    /// Check if `self` is the post-child-write state of a pointer (is `Active`).
+    pub fn is_active(&self) -> bool {
+        self.inner == Active
+    }
 
     /// 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!
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 ff4589657af..90bd1103218 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
@@ -530,13 +530,11 @@ impl<'tcx> Tree {
         span: Span,        // diagnostics
     ) -> InterpResult<'tcx> {
         self.perform_access(
-            AccessKind::Write,
             tag,
-            Some(access_range),
+            Some((access_range, AccessKind::Write, diagnostics::AccessCause::Dealloc)),
             global,
             alloc_id,
             span,
-            diagnostics::AccessCause::Dealloc,
         )?;
         for (perms_range, perms) in self.rperms.iter_mut(access_range.start, access_range.size) {
             TreeVisitor { nodes: &mut self.nodes, tag_mapping: &self.tag_mapping, perms }
@@ -570,12 +568,16 @@ impl<'tcx> Tree {
     }
 
     /// Map the per-node and per-location `LocationState::perform_access`
-    /// to each location of `access_range`, on every tag of the allocation.
+    /// to each location of the first component of `access_range_and_kind`,
+    /// on every tag of the allocation.
     ///
-    /// If `access_range` is `None`, this is interpreted as the special
+    /// If `access_range_and_kind` is `None`, this is interpreted as the special
     /// access that is applied on protector release:
     /// - the access will be applied only to initialized locations of the allocation,
-    /// - and it will not be visible to children.
+    /// - it will not be visible to children,
+    /// - it will be recorded as a `FnExit` diagnostic access
+    /// - and it will be a read except if the location is `Active`, i.e. has been written to,
+    ///   in which case it will be a write.
     ///
     /// `LocationState::perform_access` will take care of raising transition
     /// errors and updating the `initialized` status of each location,
@@ -585,13 +587,11 @@ impl<'tcx> Tree {
     /// - recording the history.
     pub fn perform_access(
         &mut self,
-        access_kind: AccessKind,
         tag: BorTag,
-        access_range: Option<AllocRange>,
+        access_range_and_kind: Option<(AllocRange, AccessKind, diagnostics::AccessCause)>,
         global: &GlobalState,
-        alloc_id: AllocId,                      // diagnostics
-        span: Span,                             // diagnostics
-        access_cause: diagnostics::AccessCause, // diagnostics
+        alloc_id: AllocId, // diagnostics
+        span: Span,        // diagnostics
     ) -> InterpResult<'tcx> {
         use std::ops::Range;
         // Performs the per-node work:
@@ -605,6 +605,8 @@ impl<'tcx> Tree {
         // `perms_range` is only for diagnostics (it is the range of
         // the `RangeMap` on which we are currently working).
         let node_app = |perms_range: Range<u64>,
+                        access_kind: AccessKind,
+                        access_cause: diagnostics::AccessCause,
                         args: NodeAppArgs<'_>|
          -> Result<ContinueTraversal, TransitionError> {
             let NodeAppArgs { node, mut perm, rel_pos } = args;
@@ -618,14 +620,13 @@ impl<'tcx> Tree {
 
             let protected = global.borrow().protected_tags.contains_key(&node.tag);
             let transition = old_state.perform_access(access_kind, rel_pos, protected)?;
-
             // Record the event as part of the history
             if !transition.is_noop() {
                 node.debug_info.history.push(diagnostics::Event {
                     transition,
                     is_foreign: rel_pos.is_foreign(),
                     access_cause,
-                    access_range,
+                    access_range: access_range_and_kind.map(|x| x.0),
                     transition_range: perms_range,
                     span,
                 });
@@ -636,6 +637,7 @@ impl<'tcx> Tree {
         // Error handler in case `node_app` goes wrong.
         // Wraps the faulty transition in more context for diagnostics.
         let err_handler = |perms_range: Range<u64>,
+                           access_cause: diagnostics::AccessCause,
                            args: ErrHandlerArgs<'_, TransitionError>|
          -> InterpError<'tcx> {
             let ErrHandlerArgs { error_kind, conflicting_info, accessed_info } = args;
@@ -650,7 +652,7 @@ impl<'tcx> Tree {
             .build()
         };
 
-        if let Some(access_range) = access_range {
+        if let Some((access_range, access_kind, access_cause)) = access_range_and_kind {
             // Default branch: this is a "normal" access through a known range.
             // We iterate over affected locations and traverse the tree for each of them.
             for (perms_range, perms) in self.rperms.iter_mut(access_range.start, access_range.size)
@@ -658,8 +660,8 @@ impl<'tcx> Tree {
                 TreeVisitor { nodes: &mut self.nodes, tag_mapping: &self.tag_mapping, perms }
                     .traverse_parents_this_children_others(
                         tag,
-                        |args| node_app(perms_range.clone(), args),
-                        |args| err_handler(perms_range.clone(), args),
+                        |args| node_app(perms_range.clone(), access_kind, access_cause, args),
+                        |args| err_handler(perms_range.clone(), access_cause, args),
                     )?;
             }
         } else {
@@ -678,11 +680,14 @@ impl<'tcx> Tree {
                 if let Some(p) = perms.get(idx)
                     && 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(
                         tag,
-                        |args| node_app(perms_range.clone(), args),
-                        |args| err_handler(perms_range.clone(), args),
+                        |args| node_app(perms_range.clone(), access_kind, access_cause, args),
+                        |args| err_handler(perms_range.clone(), access_cause, args),
                     )?;
                 }
             }
diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs
index 6a2b99825ad..718daf93ea0 100644
--- a/src/tools/miri/src/concurrency/thread.rs
+++ b/src/tools/miri/src/concurrency/thread.rs
@@ -643,8 +643,7 @@ impl<'tcx> ThreadManager<'tcx> {
         if !self.threads[joined_thread_id].state.is_terminated() {
             trace!(
                 "{:?} blocked on {:?} when trying to join",
-                self.active_thread,
-                joined_thread_id
+                self.active_thread, joined_thread_id
             );
             // The joined thread is still running, we need to wait for it.
             // Unce we get unblocked, perform the appropriate synchronization.
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index 12fb76f3972..647d7d44bb1 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -227,8 +227,8 @@ pub fn report_error<'tcx>(
         let helps = match info {
             UnsupportedInIsolation(_) =>
                 vec![
-                    (None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation;")),
-                    (None, format!("or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning")),
+                    (None, format!("set `MIRIFLAGS=-Zmiri-disable-isolation` to disable isolation;")),
+                    (None, format!("or set `MIRIFLAGS=-Zmiri-isolation-error=warn` to make Miri return an error code from isolated operations (if supported for that operation) and continue with a warning")),
                 ],
             UnsupportedForeignItem(_) => {
                 vec![
@@ -311,7 +311,9 @@ pub fn report_error<'tcx>(
             ResourceExhaustion(_) => "resource exhaustion",
             Unsupported(
                 // We list only the ones that can actually happen.
-                UnsupportedOpInfo::Unsupported(_) | UnsupportedOpInfo::UnsizedLocal,
+                UnsupportedOpInfo::Unsupported(_)
+                | UnsupportedOpInfo::UnsizedLocal
+                | UnsupportedOpInfo::ExternTypeField,
             ) => "unsupported operation",
             InvalidProgram(
                 // We list only the ones that can actually happen.
@@ -463,19 +465,22 @@ pub fn report_leaks<'tcx>(
 ) {
     let mut any_pruned = false;
     for (id, kind, mut alloc) in leaks {
+        let mut title = format!(
+            "memory leaked: {id:?} ({}, size: {:?}, align: {:?})",
+            kind,
+            alloc.size().bytes(),
+            alloc.align.bytes()
+        );
         let Some(backtrace) = alloc.extra.backtrace.take() else {
+            ecx.tcx.dcx().err(title);
             continue;
         };
+        title.push_str(", allocated here:");
         let (backtrace, pruned) = prune_stacktrace(backtrace, &ecx.machine);
         any_pruned |= pruned;
         report_msg(
             DiagLevel::Error,
-            format!(
-                "memory leaked: {id:?} ({}, size: {:?}, align: {:?}), allocated here:",
-                kind,
-                alloc.size().bytes(),
-                alloc.align.bytes()
-            ),
+            title,
             vec![],
             vec![],
             vec![],
@@ -642,15 +647,11 @@ impl<'tcx> MiriMachine<'tcx> {
                     (
                         None,
                         format!(
-                            "This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`,"
+                            "This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, which means that Miri might miss pointer bugs in this program."
                         ),
                     ),
                     (
                         None,
-                        format!("which means that Miri might miss pointer bugs in this program."),
-                    ),
-                    (
-                        None,
                         format!(
                             "See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation."
                         ),
@@ -664,13 +665,13 @@ impl<'tcx> MiriMachine<'tcx> {
                     (
                         None,
                         format!(
-                            "You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `with_exposed_provenance` semantics."
+                            "You can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics."
                         ),
                     ),
                     (
                         None,
                         format!(
-                            "Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning."
+                            "Alternatively, `MIRIFLAGS=-Zmiri-permissive-provenance` disables this warning."
                         ),
                     ),
                 ],
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index 35f7f43f123..9142b8b5fdb 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -303,7 +303,7 @@ pub fn create_ecx<'tcx>(
         let mut argvs = Vec::<Immediate<Provenance>>::with_capacity(config.args.len());
         for arg in config.args.iter() {
             // Make space for `0` terminator.
-            let size = u64::try_from(arg.len()).unwrap().checked_add(1).unwrap();
+            let size = u64::try_from(arg.len()).unwrap().strict_add(1);
             let arg_type = Ty::new_array(tcx, tcx.types.u8, size);
             let arg_place =
                 ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Machine.into())?;
@@ -375,7 +375,7 @@ pub fn create_ecx<'tcx>(
             });
             let main_ret_ty = tcx.fn_sig(entry_id).no_bound_vars().unwrap().output();
             let main_ret_ty = main_ret_ty.no_bound_vars().unwrap();
-            let start_instance = ty::Instance::resolve(
+            let start_instance = ty::Instance::try_resolve(
                 tcx,
                 ty::ParamEnv::reveal_all(),
                 start_id,
@@ -468,7 +468,7 @@ pub fn eval_entry<'tcx>(
         // Check for thread leaks.
         if !ecx.have_all_terminated() {
             tcx.dcx().err("the main thread terminated without waiting for all remaining threads");
-            tcx.dcx().note("pass `-Zmiri-ignore-leaks` to disable this check");
+            tcx.dcx().note("set `MIRIFLAGS=-Zmiri-ignore-leaks` to disable this check");
             return None;
         }
         // Check for memory leaks.
@@ -476,14 +476,7 @@ pub fn eval_entry<'tcx>(
         let leaks = ecx.find_leaked_allocations(&ecx.machine.static_roots);
         if !leaks.is_empty() {
             report_leaks(&ecx, leaks);
-            let leak_message = "the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check";
-            if ecx.machine.collect_leak_backtraces {
-                // If we are collecting leak backtraces, each leak is a distinct error diagnostic.
-                tcx.dcx().note(leak_message);
-            } else {
-                // If we do not have backtraces, we just report an error without any span.
-                tcx.dcx().err(leak_message);
-            };
+            tcx.dcx().note("set `MIRIFLAGS=-Zmiri-ignore-leaks` to disable this check");
             // Ignore the provided return code - let the reported error
             // determine the return code.
             return None;
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index 843aff02495..590e8984e99 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -14,6 +14,7 @@ use rustc_hir::{
     def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE},
 };
 use rustc_index::IndexVec;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_middle::middle::exported_symbols::ExportedSymbol;
 use rustc_middle::mir;
@@ -23,7 +24,7 @@ use rustc_middle::ty::{
     FloatTy, IntTy, Ty, TyCtxt, UintTy,
 };
 use rustc_session::config::CrateType;
-use rustc_span::{sym, Span, Symbol};
+use rustc_span::{Span, Symbol};
 use rustc_target::abi::{Align, FieldIdx, FieldsShape, Size, Variants};
 use rustc_target::spec::abi::Abi;
 
@@ -163,22 +164,39 @@ pub fn iter_exported_symbols<'tcx>(
     tcx: TyCtxt<'tcx>,
     mut f: impl FnMut(CrateNum, DefId) -> InterpResult<'tcx>,
 ) -> InterpResult<'tcx> {
+    // First, the symbols in the local crate. We can't use `exported_symbols` here as that
+    // skips `#[used]` statics (since `reachable_set` skips them in binary crates).
+    // So we walk all HIR items ourselves instead.
+    let crate_items = tcx.hir_crate_items(());
+    for def_id in crate_items.definitions() {
+        let exported = tcx.def_kind(def_id).has_codegen_attrs() && {
+            let codegen_attrs = tcx.codegen_fn_attrs(def_id);
+            codegen_attrs.contains_extern_indicator()
+                || codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
+                || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED)
+                || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
+        };
+        if exported {
+            f(LOCAL_CRATE, def_id.into())?;
+        }
+    }
+
+    // Next, all our dependencies.
     // `dependency_formats` includes all the transitive informations needed to link a crate,
     // which is what we need here since we need to dig out `exported_symbols` from all transitive
     // dependencies.
     let dependency_formats = tcx.dependency_formats(());
+    // Find the dependencies of the executable we are running.
     let dependency_format = dependency_formats
         .iter()
         .find(|(crate_type, _)| *crate_type == CrateType::Executable)
         .expect("interpreting a non-executable crate");
-    for cnum in iter::once(LOCAL_CRATE).chain(dependency_format.1.iter().enumerate().filter_map(
-        |(num, &linkage)| {
-            // We add 1 to the number because that's what rustc also does everywhere it
-            // calls `CrateNum::new`...
-            #[allow(clippy::arithmetic_side_effects)]
-            (linkage != Linkage::NotLinked).then_some(CrateNum::new(num + 1))
-        },
-    )) {
+    for cnum in dependency_format.1.iter().enumerate().filter_map(|(num, &linkage)| {
+        // We add 1 to the number because that's what rustc also does everywhere it
+        // calls `CrateNum::new`...
+        #[allow(clippy::arithmetic_side_effects)]
+        (linkage != Linkage::NotLinked).then_some(CrateNum::new(num + 1))
+    }) {
         // We can ignore `_export_info` here: we are a Rust crate, and everything is exported
         // from a Rust crate.
         for &(symbol, _export_info) in tcx.exported_symbols(cnum) {
@@ -273,6 +291,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
     /// Helper function to get a `libc` constant as a `Scalar`.
     fn eval_libc(&self, name: &str) -> Scalar {
+        if self.eval_context_ref().tcx.sess.target.os == "windows" {
+            panic!(
+                "`libc` crate is not reliably available on Windows targets; Miri should not use it there"
+            );
+        }
         self.eval_path_scalar(&["libc", name])
     }
 
@@ -316,6 +339,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     /// Helper function to get the `TyAndLayout` of a `libc` type
     fn libc_ty_layout(&self, name: &str) -> TyAndLayout<'tcx> {
         let this = self.eval_context_ref();
+        if this.tcx.sess.target.os == "windows" {
+            panic!(
+                "`libc` crate is not reliably available on Windows targets; Miri should not use it there"
+            );
+        }
         let ty = this
             .resolve_path(&["libc", name], Namespace::TypeNS)
             .ty(*this.tcx, ty::ParamEnv::reveal_all());
@@ -963,7 +991,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null
         // terminator to memory using the `ptr` pointer would cause an out-of-bounds access.
         let string_length = u64::try_from(c_str.len()).unwrap();
-        let string_length = string_length.checked_add(1).unwrap();
+        let string_length = string_length.strict_add(1);
         if size < string_length {
             return Ok((false, string_length));
         }
@@ -1027,7 +1055,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required
         // 0x0000 terminator to memory would cause an out-of-bounds access.
         let string_length = u64::try_from(wide_str.len()).unwrap();
-        let string_length = string_length.checked_add(1).unwrap();
+        let string_length = string_length.strict_add(1);
         if size < string_length {
             return Ok((false, string_length));
         }
@@ -1048,7 +1076,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     /// Always returns a `Vec<u32>` no matter the size of `wchar_t`.
     fn read_wchar_t_str(&self, ptr: Pointer) -> InterpResult<'tcx, Vec<u32>> {
         let this = self.eval_context_ref();
-        let wchar_t = this.libc_ty_layout("wchar_t");
+        let wchar_t = if this.tcx.sess.target.os == "windows" {
+            // We don't have libc on Windows so we have to hard-code the type ourselves.
+            this.machine.layouts.u16
+        } else {
+            this.libc_ty_layout("wchar_t")
+        };
         self.read_c_str_with_char_size(ptr, wchar_t.size, wchar_t.align.abi)
     }
 
@@ -1149,14 +1182,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         this.alloc_mark_immutable(provenance.get_alloc_id().unwrap()).unwrap();
     }
 
-    fn item_link_name(&self, def_id: DefId) -> Symbol {
-        let tcx = self.eval_context_ref().tcx;
-        match tcx.get_attrs(def_id, sym::link_name).filter_map(|a| a.value_str()).next() {
-            Some(name) => name,
-            None => tcx.item_name(def_id),
-        }
-    }
-
     /// Converts `src` from floating point to integer type `dest_ty`
     /// after rounding with mode `round`.
     /// Returns `None` if `f` is NaN or out of range.
@@ -1391,7 +1416,7 @@ pub(crate) fn windows_check_buffer_size((success, len): (bool, u64)) -> u32 {
     if success {
         // If the function succeeds, the return value is the number of characters stored in the target buffer,
         // not including the terminating null character.
-        u32::try_from(len.checked_sub(1).unwrap()).unwrap()
+        u32::try_from(len.strict_sub(1)).unwrap()
     } else {
         // If the target buffer was not large enough to hold the data, the return value is the buffer size, in characters,
         // required to hold the string and its terminating null character.
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index f8410db4dd0..8da00861f90 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -10,7 +10,7 @@
 #![feature(yeet_expr)]
 #![feature(nonzero_ops)]
 #![feature(let_chains)]
-#![feature(lint_reasons)]
+#![cfg_attr(bootstrap, feature(lint_reasons))]
 #![feature(trait_upcasting)]
 #![feature(strict_overflow_ops)]
 #![feature(is_none_or)]
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 0d91279f9f4..714d97823f4 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -954,7 +954,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
             // foreign function
             // Any needed call to `goto_block` will be performed by `emulate_foreign_item`.
             let args = ecx.copy_fn_args(args); // FIXME: Should `InPlace` arguments be reset to uninit?
-            let link_name = ecx.item_link_name(instance.def_id());
+            let link_name = Symbol::intern(ecx.tcx.symbol_name(instance).name);
             return ecx.emulate_foreign_item(link_name, abi, &args, dest, ret, unwind);
         }
 
@@ -1050,7 +1050,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         ecx: &MiriInterpCx<'tcx>,
         def_id: DefId,
     ) -> InterpResult<'tcx, StrictPointer> {
-        let link_name = ecx.item_link_name(def_id);
+        let link_name = Symbol::intern(ecx.tcx.symbol_name(Instance::mono(*ecx.tcx, def_id)).name);
         if let Some(&ptr) = ecx.machine.extern_statics.get(&link_name) {
             // Various parts of the engine rely on `get_alloc_info` for size and alignment
             // information. That uses the type information of this static.
@@ -1434,7 +1434,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         ecx: &mut InterpCx<'tcx, Self>,
         frame: Frame<'tcx, Provenance, FrameExtra<'tcx>>,
         unwinding: bool,
-    ) -> InterpResult<'tcx, StackPopJump> {
+    ) -> InterpResult<'tcx, ReturnAction> {
         if frame.extra.is_user_relevant {
             // All that we store is whether or not the frame we just removed is local, so now we
             // have no idea where the next topmost local frame is. So we recompute it.
diff --git a/src/tools/miri/src/shims/alloc.rs b/src/tools/miri/src/shims/alloc.rs
index 7b0c54d763e..a33657d33a2 100644
--- a/src/tools/miri/src/shims/alloc.rs
+++ b/src/tools/miri/src/shims/alloc.rs
@@ -5,18 +5,6 @@ use rustc_target::abi::{Align, Size};
 
 use crate::*;
 
-/// Check some basic requirements for this allocation request:
-/// non-zero size, power-of-two alignment.
-pub(super) fn check_alloc_request<'tcx>(size: u64, align: u64) -> InterpResult<'tcx> {
-    if size == 0 {
-        throw_ub_format!("creating allocation with size 0");
-    }
-    if !align.is_power_of_two() {
-        throw_ub_format!("creating allocation with non-power-of-two alignment {}", align);
-    }
-    Ok(())
-}
-
 impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
 pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     /// Returns the alignment that `malloc` would guarantee for requests of the given size.
diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs
index 06be9c1e63e..24a4b5f26a9 100644
--- a/src/tools/miri/src/shims/backtrace.rs
+++ b/src/tools/miri/src/shims/backtrace.rs
@@ -119,7 +119,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let (alloc_id, offset, _prov) = this.ptr_get_alloc_id(ptr)?;
 
         // This has to be an actual global fn ptr, not a dlsym function.
-        let fn_instance = if let Some(GlobalAlloc::Function(instance)) =
+        let fn_instance = if let Some(GlobalAlloc::Function { instance, .. }) =
             this.tcx.try_get_global_alloc(alloc_id)
         {
             instance
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index 911958e558c..9004f7efc8b 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -12,7 +12,7 @@ use rustc_target::{
     spec::abi::Abi,
 };
 
-use super::alloc::{check_alloc_request, EvalContextExt as _};
+use super::alloc::EvalContextExt as _;
 use super::backtrace::EvalContextExt as _;
 use crate::*;
 use helpers::{ToHost, ToSoft};
@@ -46,24 +46,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         unwind: mir::UnwindAction,
     ) -> InterpResult<'tcx, Option<(&'tcx mir::Body<'tcx>, ty::Instance<'tcx>)>> {
         let this = self.eval_context_mut();
-        let tcx = this.tcx.tcx;
 
         // Some shims forward to other MIR bodies.
         match link_name.as_str() {
-            // This matches calls to the foreign item `panic_impl`.
-            // The implementation is provided by the function with the `#[panic_handler]` attribute.
-            "panic_impl" => {
-                // We don't use `check_shim` here because we are just forwarding to the lang
-                // item. Argument count checking will be performed when the returned `Body` is
-                // called.
-                this.check_abi_and_shim_symbol_clash(abi, Abi::Rust, link_name)?;
-                let panic_impl_id = tcx.lang_items().panic_impl().unwrap();
-                let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id);
-                return Ok(Some((
-                    this.load_mir(panic_impl_instance.def, None)?,
-                    panic_impl_instance,
-                )));
-            }
             "__rust_alloc_error_handler" => {
                 // Forward to the right symbol that implements this function.
                 let Some(handler_kind) = this.tcx.alloc_error_handler_kind(()) else {
@@ -204,6 +189,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
 impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {}
 trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
+    /// Check some basic requirements for this allocation request:
+    /// non-zero size, power-of-two alignment.
+    fn check_rustc_alloc_request(&self, size: u64, align: u64) -> InterpResult<'tcx> {
+        let this = self.eval_context_ref();
+        if size == 0 {
+            throw_ub_format!("creating allocation with size 0");
+        }
+        if i128::from(size) > this.tcx.data_layout.pointer_size.signed_int_max() {
+            throw_ub_format!("creating an allocation larger than half the address space");
+        }
+        if !align.is_power_of_two() {
+            throw_ub_format!("creating allocation with non-power-of-two alignment {}", align);
+        }
+        Ok(())
+    }
+
     fn emulate_foreign_item_inner(
         &mut self,
         link_name: Symbol,
@@ -386,7 +387,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 });
                 let (_, addr) = ptr.into_parts(); // we know the offset is absolute
                 // Cannot panic since `align` is a power of 2 and hence non-zero.
-                if addr.bytes().checked_rem(align.bytes()).unwrap() != 0 {
+                if addr.bytes().strict_rem(align.bytes()) != 0 {
                     throw_unsup_format!(
                         "`miri_promise_symbolic_alignment`: pointer is not actually aligned"
                     );
@@ -462,7 +463,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     let size = this.read_target_usize(size)?;
                     let align = this.read_target_usize(align)?;
 
-                    check_alloc_request(size, align)?;
+                    this.check_rustc_alloc_request(size, align)?;
 
                     let memory_kind = match link_name.as_str() {
                         "__rust_alloc" => MiriMemoryKind::Rust,
@@ -496,7 +497,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     let size = this.read_target_usize(size)?;
                     let align = this.read_target_usize(align)?;
 
-                    check_alloc_request(size, align)?;
+                    this.check_rustc_alloc_request(size, align)?;
 
                     let ptr = this.allocate_ptr(
                         Size::from_bytes(size),
@@ -560,7 +561,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     let new_size = this.read_target_usize(new_size)?;
                     // No need to check old_size; we anyway check that they match the allocation.
 
-                    check_alloc_request(new_size, align)?;
+                    this.check_rustc_alloc_request(new_size, align)?;
 
                     let align = Align::from_bytes(align).unwrap();
                     let new_ptr = this.reallocate_ptr(
@@ -698,7 +699,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // That is probably overly cautious, but there also is no fundamental
                 // reason to have `strcpy` destroy pointer provenance.
                 // This reads at least 1 byte, so we are already enforcing that this is a valid pointer.
-                let n = this.read_c_str(ptr_src)?.len().checked_add(1).unwrap();
+                let n = this.read_c_str(ptr_src)?.len().strict_add(1);
                 this.mem_copy(ptr_src, ptr_dest, Size::from_bytes(n), true)?;
                 this.write_pointer(ptr_dest, dest)?;
             }
diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs
index ef832f5bbbd..306dce5edcd 100644
--- a/src/tools/miri/src/shims/panic.rs
+++ b/src/tools/miri/src/shims/panic.rs
@@ -113,7 +113,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         &mut self,
         mut extra: FrameExtra<'tcx>,
         unwinding: bool,
-    ) -> InterpResult<'tcx, StackPopJump> {
+    ) -> InterpResult<'tcx, ReturnAction> {
         let this = self.eval_context_mut();
         trace!("handle_stack_pop_unwind(extra = {:?}, unwinding = {})", extra, unwinding);
 
@@ -150,9 +150,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             )?;
 
             // We pushed a new stack frame, the engine should not do any jumping now!
-            Ok(StackPopJump::NoJump)
+            Ok(ReturnAction::NoJump)
         } else {
-            Ok(StackPopJump::Normal)
+            Ok(ReturnAction::Normal)
         }
     }
 
diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs
index ae17196f0b7..e8f906d37e8 100644
--- a/src/tools/miri/src/shims/time.rs
+++ b/src/tools/miri/src/shims/time.rs
@@ -165,7 +165,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 ("tm_hour", dt.hour().into()),
                 ("tm_mday", dt.day().into()),
                 ("tm_mon", dt.month0().into()),
-                ("tm_year", dt.year().checked_sub(1900).unwrap().into()),
+                ("tm_year", dt.year().strict_sub(1900).into()),
                 ("tm_wday", dt.weekday().num_days_from_sunday().into()),
                 ("tm_yday", dt.ordinal0().into()),
                 ("tm_isdst", tm_isdst),
diff --git a/src/tools/miri/src/shims/unix/env.rs b/src/tools/miri/src/shims/unix/env.rs
index 2f78d0f4296..405431f4327 100644
--- a/src/tools/miri/src/shims/unix/env.rs
+++ b/src/tools/miri/src/shims/unix/env.rs
@@ -81,10 +81,8 @@ impl<'tcx> UnixEnvVars<'tcx> {
             return Ok(None);
         };
         // The offset is used to strip the "{name}=" part of the string.
-        let var_ptr = var_ptr.offset(
-            Size::from_bytes(u64::try_from(name.len()).unwrap().checked_add(1).unwrap()),
-            ecx,
-        )?;
+        let var_ptr = var_ptr
+            .offset(Size::from_bytes(u64::try_from(name.len()).unwrap().strict_add(1)), ecx)?;
         Ok(Some(var_ptr))
     }
 
diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs
index b6ac841dc9f..7f6a0978103 100644
--- a/src/tools/miri/src/shims/unix/fd.rs
+++ b/src/tools/miri/src/shims/unix/fd.rs
@@ -240,7 +240,7 @@ impl FdTable {
         let new_fd = candidate_new_fd.unwrap_or_else(|| {
             // find_map ran out of BTreeMap entries before finding a free fd, use one plus the
             // maximum fd in the map
-            self.fds.last_key_value().map(|(fd, _)| fd.checked_add(1).unwrap()).unwrap_or(min_fd)
+            self.fds.last_key_value().map(|(fd, _)| fd.strict_add(1)).unwrap_or(min_fd)
         });
 
         self.fds.try_insert(new_fd, file_handle).unwrap();
@@ -273,6 +273,32 @@ impl FdTable {
 
 impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
 pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
+    fn dup(&mut self, old_fd: i32) -> InterpResult<'tcx, i32> {
+        let this = self.eval_context_mut();
+
+        let Some(dup_fd) = this.machine.fds.dup(old_fd) else {
+            return this.fd_not_found();
+        };
+        Ok(this.machine.fds.insert_fd_with_min_fd(dup_fd, 0))
+    }
+
+    fn dup2(&mut self, old_fd: i32, new_fd: i32) -> InterpResult<'tcx, i32> {
+        let this = self.eval_context_mut();
+
+        let Some(dup_fd) = this.machine.fds.dup(old_fd) else {
+            return this.fd_not_found();
+        };
+        if new_fd != old_fd {
+            // Close new_fd if it is previously opened.
+            // If old_fd and new_fd point to the same description, then `dup_fd` ensures we keep the underlying file description alive.
+            if let Some(file_descriptor) = this.machine.fds.fds.insert(new_fd, dup_fd) {
+                // Ignore close error (not interpreter's) according to dup2() doc.
+                file_descriptor.close(this.machine.communicate())?.ok();
+            }
+        }
+        Ok(new_fd)
+    }
+
     fn fcntl(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, i32> {
         let this = self.eval_context_mut();
 
@@ -334,14 +360,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         let fd = this.read_scalar(fd_op)?.to_i32()?;
 
-        Ok(Scalar::from_i32(if let Some(file_descriptor) = this.machine.fds.remove(fd) {
-            let result = file_descriptor.close(this.machine.communicate())?;
-            // return `0` if close is successful
-            let result = result.map(|()| 0i32);
-            this.try_unwrap_io_result(result)?
-        } else {
-            this.fd_not_found()?
-        }))
+        let Some(file_descriptor) = this.machine.fds.remove(fd) else {
+            return Ok(Scalar::from_i32(this.fd_not_found()?));
+        };
+        let result = file_descriptor.close(this.machine.communicate())?;
+        // return `0` if close is successful
+        let result = result.map(|()| 0i32);
+        Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
     }
 
     /// Function used when a file descriptor does not exist. It returns `Ok(-1)`and sets
diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs
index 2282099fa0d..2421f9244f3 100644
--- a/src/tools/miri/src/shims/unix/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/foreign_items.rs
@@ -51,7 +51,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern.
         #[rustfmt::skip]
         match link_name.as_str() {
-            // Environment variables
+            // Environment related shims
             "getenv" => {
                 let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.getenv(name)?;
@@ -78,6 +78,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let result = this.chdir(path)?;
                 this.write_scalar(Scalar::from_i32(result), dest)?;
             }
+            "getpid" => {
+                let [] = this.check_shim(abi, Abi::C { unwind: false}, link_name, args)?;
+                let result = this.getpid()?;
+                this.write_scalar(Scalar::from_i32(result), dest)?;
+            }
 
             // File descriptors
             "read" => {
@@ -110,6 +115,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let result = this.fcntl(args)?;
                 this.write_scalar(Scalar::from_i32(result), dest)?;
             }
+            "dup" => {
+                let [old_fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let old_fd = this.read_scalar(old_fd)?.to_i32()?;
+                let new_fd = this.dup(old_fd)?;
+                this.write_scalar(Scalar::from_i32(new_fd), dest)?;
+            }
+            "dup2" => {
+                let [old_fd, new_fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let old_fd = this.read_scalar(old_fd)?.to_i32()?;
+                let new_fd = this.read_scalar(new_fd)?.to_i32()?;
+                let result = this.dup2(old_fd, new_fd)?;
+                this.write_scalar(Scalar::from_i32(result), dest)?;
+            }
 
             // File and file system access
             "open" | "open64" => {
@@ -583,11 +601,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let ret = if complete { 0 } else { this.eval_libc_i32("ERANGE") };
                 this.write_int(ret, dest)?;
             }
-            "getpid" => {
-                let [] = this.check_shim(abi, Abi::C { unwind: false}, link_name, args)?;
-                let result = this.getpid()?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
-            }
             "getentropy" => {
                 // This function is non-standard but exists with the same signature and behavior on
                 // Linux, macOS, FreeBSD and Solaris/Illumos.
diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs
index 262e71756c6..e34aa5c09df 100644
--- a/src/tools/miri/src/shims/unix/fs.rs
+++ b/src/tools/miri/src/shims/unix/fs.rs
@@ -395,7 +395,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Isolation check is done via `FileDescriptor` trait.
 
         let seek_from = if whence == this.eval_libc_i32("SEEK_SET") {
-            SeekFrom::Start(u64::try_from(offset).unwrap())
+            if offset < 0 {
+                // Negative offsets return `EINVAL`.
+                let einval = this.eval_libc("EINVAL");
+                this.set_last_error(einval)?;
+                return Ok(Scalar::from_i64(-1));
+            } else {
+                SeekFrom::Start(u64::try_from(offset).unwrap())
+            }
         } else if whence == this.eval_libc_i32("SEEK_CUR") {
             SeekFrom::Current(i64::try_from(offset).unwrap())
         } else if whence == this.eval_libc_i32("SEEK_END") {
diff --git a/src/tools/miri/src/shims/unix/socket.rs b/src/tools/miri/src/shims/unix/socket.rs
index c639ea2f846..6d3d63b4efa 100644
--- a/src/tools/miri/src/shims/unix/socket.rs
+++ b/src/tools/miri/src/shims/unix/socket.rs
@@ -116,7 +116,7 @@ impl FileDescription for SocketPair {
         };
         let mut writebuf = writebuf.borrow_mut();
         let data_size = writebuf.buf.len();
-        let available_space = MAX_SOCKETPAIR_BUFFER_CAPACITY.checked_sub(data_size).unwrap();
+        let available_space = MAX_SOCKETPAIR_BUFFER_CAPACITY.strict_sub(data_size);
         if available_space == 0 {
             if self.is_nonblock {
                 // Non-blocking socketpair with a full buffer.
diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs
index bfa14bcb5fa..71f6a2bc033 100644
--- a/src/tools/miri/src/shims/windows/foreign_items.rs
+++ b/src/tools/miri/src/shims/windows/foreign_items.rs
@@ -138,6 +138,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let result = this.GetUserProfileDirectoryW(token, buf, size)?;
                 this.write_scalar(result, dest)?;
             }
+            "GetCurrentProcessId" => {
+                let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
+                let result = this.GetCurrentProcessId()?;
+                this.write_int(result, dest)?;
+            }
 
             // File related shims
             "NtWriteFile" => {
@@ -647,7 +652,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     // If the function succeeds, the return value is the length of the string that
                     // is copied to the buffer, in characters, not including the terminating null
                     // character.
-                    this.write_int(size_needed.checked_sub(1).unwrap(), dest)?;
+                    this.write_int(size_needed.strict_sub(1), dest)?;
                 } else {
                     // If the buffer is too small to hold the module name, the string is truncated
                     // to nSize characters including the terminating null character, the function
@@ -689,7 +694,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     throw_unsup_format!("FormatMessageW: buffer not big enough");
                 }
                 // The return value is the number of characters stored *excluding* the null terminator.
-                this.write_int(length.checked_sub(1).unwrap(), dest)?;
+                this.write_int(length.strict_sub(1), dest)?;
             }
 
             // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
@@ -743,11 +748,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // Any non zero value works for the stdlib. This is just used for stack overflows anyway.
                 this.write_int(1, dest)?;
             }
-            "GetCurrentProcessId" if this.frame_in_std() => {
-                let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
-                let result = this.GetCurrentProcessId()?;
-                this.write_int(result, dest)?;
-            }
             // this is only callable from std because we know that std ignores the return value
             "SwitchToThread" if this.frame_in_std() => {
                 let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
@@ -758,6 +758,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_null(dest)?;
             }
 
+            "_Unwind_RaiseException" => {
+                // This is not formally part of POSIX, but it is very wide-spread on POSIX systems.
+                // It was originally specified as part of the Itanium C++ ABI:
+                // https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#base-throw.
+                // MinGW implements _Unwind_RaiseException on top of SEH exceptions.
+                if this.tcx.sess.target.env != "gnu" {
+                    throw_unsup_format!(
+                        "`_Unwind_RaiseException` is not supported on non-MinGW Windows",
+                    );
+                }
+                // This function looks and behaves excatly like miri_start_unwind.
+                let [payload] = this.check_shim(abi, Abi::C { unwind: true }, link_name, args)?;
+                this.handle_miri_start_unwind(payload)?;
+                return Ok(EmulateItemResult::NeedsUnwind);
+            }
+
             _ => return Ok(EmulateItemResult::NotSupported),
         }
 
diff --git a/src/tools/miri/src/shims/windows/handle.rs b/src/tools/miri/src/shims/windows/handle.rs
index 58c8683ff27..ec461a4cd36 100644
--- a/src/tools/miri/src/shims/windows/handle.rs
+++ b/src/tools/miri/src/shims/windows/handle.rs
@@ -74,7 +74,7 @@ impl Handle {
     /// None of this layout is guaranteed to applications by Windows or Miri.
     fn to_packed(self) -> u32 {
         let disc_size = Self::packed_disc_size();
-        let data_size = u32::BITS.checked_sub(disc_size).unwrap();
+        let data_size = u32::BITS.strict_sub(disc_size);
 
         let discriminant = self.discriminant();
         let data = self.data();
@@ -103,7 +103,7 @@ impl Handle {
     /// see docs for `to_packed`
     fn from_packed(handle: u32) -> Option<Self> {
         let disc_size = Self::packed_disc_size();
-        let data_size = u32::BITS.checked_sub(disc_size).unwrap();
+        let data_size = u32::BITS.strict_sub(disc_size);
 
         // the lower `data_size` bits of this mask are 1
         #[allow(clippy::arithmetic_side_effects)] // cannot overflow
diff --git a/src/tools/miri/src/shims/x86/avx.rs b/src/tools/miri/src/shims/x86/avx.rs
index 0d2977b7b6f..f36bb4826e4 100644
--- a/src/tools/miri/src/shims/x86/avx.rs
+++ b/src/tools/miri/src/shims/x86/avx.rs
@@ -338,6 +338,17 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
                 this.write_scalar(Scalar::from_i32(res.into()), dest)?;
             }
+            // Used to implement the `_mm256_zeroupper` and `_mm256_zeroall` functions.
+            // These function clear out the upper 128 bits of all avx registers or
+            // zero out all avx registers respectively.
+            "vzeroupper" | "vzeroall" => {
+                // These functions are purely a performance hint for the CPU.
+                // Any registers currently in use will be saved beforehand by the
+                // compiler, making these functions no-ops.
+
+                // The only thing that needs to be ensured is the correct calling convention.
+                let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+            }
             _ => return Ok(EmulateItemResult::NotSupported),
         }
         Ok(EmulateItemResult::NeedsReturn)
diff --git a/src/tools/miri/src/shims/x86/avx2.rs b/src/tools/miri/src/shims/x86/avx2.rs
index 016c525e57b..7f6c9336a97 100644
--- a/src/tools/miri/src/shims/x86/avx2.rs
+++ b/src/tools/miri/src/shims/x86/avx2.rs
@@ -75,7 +75,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 assert_eq!(dest_len, mask_len);
 
                 let mask_item_size = mask.layout.field(this, 0).size;
-                let high_bit_offset = mask_item_size.bits().checked_sub(1).unwrap();
+                let high_bit_offset = mask_item_size.bits().strict_sub(1);
 
                 let scale = this.read_scalar(scale)?.to_i8()?;
                 if !matches!(scale, 1 | 2 | 4 | 8) {
@@ -93,8 +93,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         let offset =
                             i64::try_from(this.read_scalar(&offset)?.to_int(offset.layout.size)?)
                                 .unwrap();
-                        let ptr = slice
-                            .wrapping_signed_offset(offset.checked_mul(scale).unwrap(), &this.tcx);
+                        let ptr = slice.wrapping_signed_offset(offset.strict_mul(scale), &this.tcx);
                         // Unaligned copy, which is what we want.
                         this.mem_copy(
                             ptr,
@@ -124,22 +123,22 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let (dest, dest_len) = this.mplace_to_simd(dest)?;
 
                 assert_eq!(left_len, right_len);
-                assert_eq!(dest_len.checked_mul(2).unwrap(), left_len);
+                assert_eq!(dest_len.strict_mul(2), left_len);
 
                 for i in 0..dest_len {
-                    let j1 = i.checked_mul(2).unwrap();
+                    let j1 = i.strict_mul(2);
                     let left1 = this.read_scalar(&this.project_index(&left, j1)?)?.to_i16()?;
                     let right1 = this.read_scalar(&this.project_index(&right, j1)?)?.to_i16()?;
 
-                    let j2 = j1.checked_add(1).unwrap();
+                    let j2 = j1.strict_add(1);
                     let left2 = this.read_scalar(&this.project_index(&left, j2)?)?.to_i16()?;
                     let right2 = this.read_scalar(&this.project_index(&right, j2)?)?.to_i16()?;
 
                     let dest = this.project_index(&dest, i)?;
 
                     // Multiplications are i16*i16->i32, which will not overflow.
-                    let mul1 = i32::from(left1).checked_mul(right1.into()).unwrap();
-                    let mul2 = i32::from(left2).checked_mul(right2.into()).unwrap();
+                    let mul1 = i32::from(left1).strict_mul(right1.into());
+                    let mul2 = i32::from(left2).strict_mul(right2.into());
                     // However, this addition can overflow in the most extreme case
                     // (-0x8000)*(-0x8000)+(-0x8000)*(-0x8000) = 0x80000000
                     let res = mul1.wrapping_add(mul2);
@@ -161,22 +160,22 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let (dest, dest_len) = this.mplace_to_simd(dest)?;
 
                 assert_eq!(left_len, right_len);
-                assert_eq!(dest_len.checked_mul(2).unwrap(), left_len);
+                assert_eq!(dest_len.strict_mul(2), left_len);
 
                 for i in 0..dest_len {
-                    let j1 = i.checked_mul(2).unwrap();
+                    let j1 = i.strict_mul(2);
                     let left1 = this.read_scalar(&this.project_index(&left, j1)?)?.to_u8()?;
                     let right1 = this.read_scalar(&this.project_index(&right, j1)?)?.to_i8()?;
 
-                    let j2 = j1.checked_add(1).unwrap();
+                    let j2 = j1.strict_add(1);
                     let left2 = this.read_scalar(&this.project_index(&left, j2)?)?.to_u8()?;
                     let right2 = this.read_scalar(&this.project_index(&right, j2)?)?.to_i8()?;
 
                     let dest = this.project_index(&dest, i)?;
 
                     // Multiplication of a u8 and an i8 into an i16 cannot overflow.
-                    let mul1 = i16::from(left1).checked_mul(right1.into()).unwrap();
-                    let mul2 = i16::from(left2).checked_mul(right2.into()).unwrap();
+                    let mul1 = i16::from(left1).strict_mul(right1.into());
+                    let mul2 = i16::from(left2).strict_mul(right2.into());
                     let res = mul1.saturating_add(mul2);
 
                     this.write_scalar(Scalar::from_i16(res), &dest)?;
@@ -309,7 +308,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
                 for i in 0..2 {
                     let dest = this.project_index(&dest, i)?;
-                    let src = match (imm >> i.checked_mul(4).unwrap()) & 0b11 {
+                    let src = match (imm >> i.strict_mul(4)) & 0b11 {
                         0 => this.project_index(&left, 0)?,
                         1 => this.project_index(&left, 1)?,
                         2 => this.project_index(&right, 0)?,
@@ -336,14 +335,14 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let (dest, dest_len) = this.mplace_to_simd(dest)?;
 
                 assert_eq!(left_len, right_len);
-                assert_eq!(left_len, dest_len.checked_mul(8).unwrap());
+                assert_eq!(left_len, dest_len.strict_mul(8));
 
                 for i in 0..dest_len {
                     let dest = this.project_index(&dest, i)?;
 
                     let mut acc: u16 = 0;
                     for j in 0..8 {
-                        let src_index = i.checked_mul(8).unwrap().checked_add(j).unwrap();
+                        let src_index = i.strict_mul(8).strict_add(j);
 
                         let left = this.project_index(&left, src_index)?;
                         let left = this.read_scalar(&left)?.to_u8()?;
@@ -351,7 +350,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         let right = this.project_index(&right, src_index)?;
                         let right = this.read_scalar(&right)?.to_u8()?;
 
-                        acc = acc.checked_add(left.abs_diff(right).into()).unwrap();
+                        acc = acc.strict_add(left.abs_diff(right).into());
                     }
 
                     this.write_scalar(Scalar::from_u64(acc.into()), &dest)?;
@@ -377,7 +376,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
                     let res = if right & 0x80 == 0 {
                         // Shuffle each 128-bit (16-byte) block independently.
-                        let j = u64::from(right % 16).checked_add(i & !15).unwrap();
+                        let j = u64::from(right % 16).strict_add(i & !15);
                         this.read_scalar(&this.project_index(&left, j)?)?
                     } else {
                         // If the highest bit in `right` is 1, write zero.
diff --git a/src/tools/miri/src/shims/x86/bmi.rs b/src/tools/miri/src/shims/x86/bmi.rs
new file mode 100644
index 00000000000..e70757f4397
--- /dev/null
+++ b/src/tools/miri/src/shims/x86/bmi.rs
@@ -0,0 +1,108 @@
+use rustc_span::Symbol;
+use rustc_target::spec::abi::Abi;
+
+use crate::*;
+
+impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
+pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
+    fn emulate_x86_bmi_intrinsic(
+        &mut self,
+        link_name: Symbol,
+        abi: Abi,
+        args: &[OpTy<'tcx>],
+        dest: &MPlaceTy<'tcx>,
+    ) -> InterpResult<'tcx, EmulateItemResult> {
+        let this = self.eval_context_mut();
+
+        // Prefix should have already been checked.
+        let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.bmi.").unwrap();
+
+        // The intrinsics are suffixed with the bit size of their operands.
+        let (is_64_bit, unprefixed_name) = if unprefixed_name.ends_with("64") {
+            (true, unprefixed_name.strip_suffix(".64").unwrap_or(""))
+        } else {
+            (false, unprefixed_name.strip_suffix(".32").unwrap_or(""))
+        };
+
+        // All intrinsics of the "bmi" namespace belong to the "bmi2" ISA extension.
+        // The exception is "bextr", which belongs to "bmi1".
+        let target_feature = if unprefixed_name == "bextr" { "bmi1" } else { "bmi2" };
+        this.expect_target_feature_for_intrinsic(link_name, target_feature)?;
+
+        if is_64_bit && this.tcx.sess.target.arch != "x86_64" {
+            return Ok(EmulateItemResult::NotSupported);
+        }
+
+        let [left, right] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+        let left = this.read_scalar(left)?;
+        let right = this.read_scalar(right)?;
+
+        let left = if is_64_bit { left.to_u64()? } else { u64::from(left.to_u32()?) };
+        let right = if is_64_bit { right.to_u64()? } else { u64::from(right.to_u32()?) };
+
+        let result = match unprefixed_name {
+            // Extract a contigous range of bits from an unsigned integer.
+            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_bextr_u32
+            "bextr" => {
+                let start = u32::try_from(right & 0xff).unwrap();
+                let len = u32::try_from((right >> 8) & 0xff).unwrap();
+                let shifted = left.checked_shr(start).unwrap_or(0);
+                // Keep the `len` lowest bits of `shifted`, or all bits if `len` is too big.
+                if len >= 64 { shifted } else { shifted & 1u64.wrapping_shl(len).wrapping_sub(1) }
+            }
+            // Create a copy of an unsigned integer with bits above a certain index cleared.
+            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_bzhi_u32
+            "bzhi" => {
+                let index = u32::try_from(right & 0xff).unwrap();
+                // Keep the `index` lowest bits of `left`, or all bits if `index` is too big.
+                if index >= 64 { left } else { left & 1u64.wrapping_shl(index).wrapping_sub(1) }
+            }
+            // Extract bit values of an unsigned integer at positions marked by a mask.
+            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_pext_u32
+            "pext" => {
+                let mut mask = right;
+                let mut i = 0u32;
+                let mut result = 0;
+                // Iterate over the mask one 1-bit at a time, from
+                // the least significant bit to the most significant bit.
+                while mask != 0 {
+                    // Extract the bit marked by the mask's least significant set bit
+                    // and put it at position `i` of the result.
+                    result |= u64::from(left & (1 << mask.trailing_zeros()) != 0) << i;
+                    i = i.wrapping_add(1);
+                    // Clear the least significant set bit.
+                    mask &= mask.wrapping_sub(1);
+                }
+                result
+            }
+            // Deposit bit values of an unsigned integer to positions marked by a mask.
+            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_pdep_u32
+            "pdep" => {
+                let mut mask = right;
+                let mut set = left;
+                let mut result = 0;
+                // Iterate over the mask one 1-bit at a time, from
+                // the least significant bit to the most significant bit.
+                while mask != 0 {
+                    // Put rightmost bit of `set` at the position of the current `mask` bit.
+                    result |= (set & 1) << mask.trailing_zeros();
+                    // Go to next bit of `set`.
+                    set >>= 1;
+                    // Clear the least significant set bit.
+                    mask &= mask.wrapping_sub(1);
+                }
+                result
+            }
+            _ => return Ok(EmulateItemResult::NotSupported),
+        };
+
+        let result = if is_64_bit {
+            Scalar::from_u64(result)
+        } else {
+            Scalar::from_u32(u32::try_from(result).unwrap())
+        };
+        this.write_scalar(result, dest)?;
+
+        Ok(EmulateItemResult::NeedsReturn)
+    }
+}
diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs
index b71aec02166..0bbf2a8e13e 100644
--- a/src/tools/miri/src/shims/x86/mod.rs
+++ b/src/tools/miri/src/shims/x86/mod.rs
@@ -14,6 +14,7 @@ use helpers::bool_to_simd_element;
 mod aesni;
 mod avx;
 mod avx2;
+mod bmi;
 mod sse;
 mod sse2;
 mod sse3;
@@ -34,63 +35,49 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Prefix should have already been checked.
         let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.").unwrap();
         match unprefixed_name {
-            // Used to implement the `_addcarry_u32` and `_addcarry_u64` functions.
-            // Computes a + b with input and output carry. The input carry is an 8-bit
-            // value, which is interpreted as 1 if it is non-zero. The output carry is
-            // an 8-bit value that will be 0 or 1.
+            // Used to implement the `_addcarry_u{32, 64}` and the `_subborrow_u{32, 64}` functions.
+            // Computes a + b or a - b with input and output carry/borrow. The input carry/borrow is an 8-bit
+            // value, which is interpreted as 1 if it is non-zero. The output carry/borrow is an 8-bit value that will be 0 or 1.
             // https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/addcarry-u32-addcarry-u64.html
-            "addcarry.32" | "addcarry.64" => {
-                if unprefixed_name == "addcarry.64" && this.tcx.sess.target.arch != "x86_64" {
+            // https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/subborrow-u32-subborrow-u64.html
+            "addcarry.32" | "addcarry.64" | "subborrow.32" | "subborrow.64" => {
+                if unprefixed_name.ends_with("64") && this.tcx.sess.target.arch != "x86_64" {
                     return Ok(EmulateItemResult::NotSupported);
                 }
 
-                let [c_in, a, b] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?;
-                let c_in = this.read_scalar(c_in)?.to_u8()? != 0;
-                let a = this.read_immediate(a)?;
-                let b = this.read_immediate(b)?;
-
-                let (sum, overflow1) =
-                    this.binary_op(mir::BinOp::AddWithOverflow, &a, &b)?.to_pair(this);
-                let (sum, overflow2) = this
-                    .binary_op(
-                        mir::BinOp::AddWithOverflow,
-                        &sum,
-                        &ImmTy::from_uint(c_in, a.layout),
-                    )?
-                    .to_pair(this);
-                let c_out = overflow1.to_scalar().to_bool()? | overflow2.to_scalar().to_bool()?;
-
-                this.write_scalar(Scalar::from_u8(c_out.into()), &this.project_field(dest, 0)?)?;
+                let [cb_in, a, b] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?;
+
+                let op = if unprefixed_name.starts_with("add") {
+                    mir::BinOp::AddWithOverflow
+                } else {
+                    mir::BinOp::SubWithOverflow
+                };
+
+                let (sum, cb_out) = carrying_add(this, cb_in, a, b, op)?;
+                this.write_scalar(cb_out, &this.project_field(dest, 0)?)?;
                 this.write_immediate(*sum, &this.project_field(dest, 1)?)?;
             }
-            // Used to implement the `_subborrow_u32` and `_subborrow_u64` functions.
-            // Computes a - b with input and output borrow. The input borrow is an 8-bit
-            // value, which is interpreted as 1 if it is non-zero. The output borrow is
-            // an 8-bit value that will be 0 or 1.
-            // https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/subborrow-u32-subborrow-u64.html
-            "subborrow.32" | "subborrow.64" => {
-                if unprefixed_name == "subborrow.64" && this.tcx.sess.target.arch != "x86_64" {
+
+            // Used to implement the `_addcarryx_u{32, 64}` functions. They are semantically identical with the `_addcarry_u{32, 64}` functions,
+            // except for a slightly different type signature and the requirement for the "adx" target feature.
+            // https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/addcarryx-u32-addcarryx-u64.html
+            "addcarryx.u32" | "addcarryx.u64" => {
+                this.expect_target_feature_for_intrinsic(link_name, "adx")?;
+
+                let is_u64 = unprefixed_name.ends_with("64");
+                if is_u64 && this.tcx.sess.target.arch != "x86_64" {
                     return Ok(EmulateItemResult::NotSupported);
                 }
 
-                let [b_in, a, b] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?;
-                let b_in = this.read_scalar(b_in)?.to_u8()? != 0;
-                let a = this.read_immediate(a)?;
-                let b = this.read_immediate(b)?;
-
-                let (sub, overflow1) =
-                    this.binary_op(mir::BinOp::SubWithOverflow, &a, &b)?.to_pair(this);
-                let (sub, overflow2) = this
-                    .binary_op(
-                        mir::BinOp::SubWithOverflow,
-                        &sub,
-                        &ImmTy::from_uint(b_in, a.layout),
-                    )?
-                    .to_pair(this);
-                let b_out = overflow1.to_scalar().to_bool()? | overflow2.to_scalar().to_bool()?;
-
-                this.write_scalar(Scalar::from_u8(b_out.into()), &this.project_field(dest, 0)?)?;
-                this.write_immediate(*sub, &this.project_field(dest, 1)?)?;
+                let [c_in, a, b, out] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?;
+                let out = this.deref_pointer_as(
+                    out,
+                    if is_u64 { this.machine.layouts.u64 } else { this.machine.layouts.u32 },
+                )?;
+
+                let (sum, c_out) = carrying_add(this, c_in, a, b, mir::BinOp::AddWithOverflow)?;
+                this.write_scalar(c_out, dest)?;
+                this.write_immediate(*sum, &out)?;
             }
 
             // Used to implement the `_mm_pause` function.
@@ -113,6 +100,11 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 pclmulqdq(this, left, right, imm, dest)?;
             }
 
+            name if name.starts_with("bmi.") => {
+                return bmi::EvalContextExt::emulate_x86_bmi_intrinsic(
+                    this, link_name, abi, args, dest,
+                );
+            }
             name if name.starts_with("sse.") => {
                 return sse::EvalContextExt::emulate_x86_sse_intrinsic(
                     this, link_name, abi, args, dest,
@@ -435,8 +427,7 @@ fn apply_random_float_error<F: rustc_apfloat::Float>(
 ) -> F {
     let rng = this.machine.rng.get_mut();
     // generates rand(0, 2^64) * 2^(scale - 64) = rand(0, 1) * 2^scale
-    let err =
-        F::from_u128(rng.gen::<u64>().into()).value.scalbn(err_scale.checked_sub(64).unwrap());
+    let err = F::from_u128(rng.gen::<u64>().into()).value.scalbn(err_scale.strict_sub(64));
     // give it a random sign
     let err = if rng.gen::<bool>() { -err } else { err };
     // multiple the value with (1+err)
@@ -787,7 +778,7 @@ fn split_simd_to_128bit_chunks<'tcx, P: Projectable<'tcx, Provenance>>(
 
     assert_eq!(simd_layout.size.bits() % 128, 0);
     let num_chunks = simd_layout.size.bits() / 128;
-    let items_per_chunk = simd_len.checked_div(num_chunks).unwrap();
+    let items_per_chunk = simd_len.strict_div(num_chunks);
 
     // Transmute to `[[T; items_per_chunk]; num_chunks]`
     let chunked_layout = this
@@ -835,13 +826,11 @@ fn horizontal_bin_op<'tcx>(
         for j in 0..items_per_chunk {
             // `j` is the index in `dest`
             // `k` is the index of the 2-item chunk in `src`
-            let (k, src) =
-                if j < middle { (j, &left) } else { (j.checked_sub(middle).unwrap(), &right) };
+            let (k, src) = if j < middle { (j, &left) } else { (j.strict_sub(middle), &right) };
             // `base_i` is the index of the first item of the 2-item chunk in `src`
-            let base_i = k.checked_mul(2).unwrap();
+            let base_i = k.strict_mul(2);
             let lhs = this.read_immediate(&this.project_index(src, base_i)?)?;
-            let rhs =
-                this.read_immediate(&this.project_index(src, base_i.checked_add(1).unwrap())?)?;
+            let rhs = this.read_immediate(&this.project_index(src, base_i.strict_add(1))?)?;
 
             let res = if saturating {
                 Immediate::from(this.saturating_arith(which, &lhs, &rhs)?)
@@ -894,7 +883,7 @@ fn conditional_dot_product<'tcx>(
         // for the initial value because the representation of 0.0 is all zero bits.
         let mut sum = ImmTy::from_int(0u8, element_layout);
         for j in 0..items_per_chunk {
-            if imm & (1 << j.checked_add(4).unwrap()) != 0 {
+            if imm & (1 << j.strict_add(4)) != 0 {
                 let left = this.read_immediate(&this.project_index(&left, j)?)?;
                 let right = this.read_immediate(&this.project_index(&right, j)?)?;
 
@@ -965,7 +954,7 @@ fn test_high_bits_masked<'tcx>(
 
     assert_eq!(op_len, mask_len);
 
-    let high_bit_offset = op.layout.field(this, 0).size.bits().checked_sub(1).unwrap();
+    let high_bit_offset = op.layout.field(this, 0).size.bits().strict_sub(1);
 
     let mut direct = true;
     let mut negated = true;
@@ -996,7 +985,7 @@ fn mask_load<'tcx>(
     assert_eq!(dest_len, mask_len);
 
     let mask_item_size = mask.layout.field(this, 0).size;
-    let high_bit_offset = mask_item_size.bits().checked_sub(1).unwrap();
+    let high_bit_offset = mask_item_size.bits().strict_sub(1);
 
     let ptr = this.read_pointer(ptr)?;
     for i in 0..dest_len {
@@ -1029,7 +1018,7 @@ fn mask_store<'tcx>(
     assert_eq!(value_len, mask_len);
 
     let mask_item_size = mask.layout.field(this, 0).size;
-    let high_bit_offset = mask_item_size.bits().checked_sub(1).unwrap();
+    let high_bit_offset = mask_item_size.bits().strict_sub(1);
 
     let ptr = this.read_pointer(ptr)?;
     for i in 0..value_len {
@@ -1071,15 +1060,15 @@ fn mpsadbw<'tcx>(
     let (_, _, right) = split_simd_to_128bit_chunks(this, right)?;
     let (_, dest_items_per_chunk, dest) = split_simd_to_128bit_chunks(this, dest)?;
 
-    assert_eq!(op_items_per_chunk, dest_items_per_chunk.checked_mul(2).unwrap());
+    assert_eq!(op_items_per_chunk, dest_items_per_chunk.strict_mul(2));
 
     let imm = this.read_scalar(imm)?.to_uint(imm.layout.size)?;
     // Bit 2 of `imm` specifies the offset for indices of `left`.
     // The offset is 0 when the bit is 0 or 4 when the bit is 1.
-    let left_offset = u64::try_from((imm >> 2) & 1).unwrap().checked_mul(4).unwrap();
+    let left_offset = u64::try_from((imm >> 2) & 1).unwrap().strict_mul(4);
     // Bits 0..=1 of `imm` specify the offset for indices of
     // `right` in blocks of 4 elements.
-    let right_offset = u64::try_from(imm & 0b11).unwrap().checked_mul(4).unwrap();
+    let right_offset = u64::try_from(imm & 0b11).unwrap().strict_mul(4);
 
     for i in 0..num_chunks {
         let left = this.project_index(&left, i)?;
@@ -1087,18 +1076,16 @@ fn mpsadbw<'tcx>(
         let dest = this.project_index(&dest, i)?;
 
         for j in 0..dest_items_per_chunk {
-            let left_offset = left_offset.checked_add(j).unwrap();
+            let left_offset = left_offset.strict_add(j);
             let mut res: u16 = 0;
             for k in 0..4 {
                 let left = this
-                    .read_scalar(&this.project_index(&left, left_offset.checked_add(k).unwrap())?)?
+                    .read_scalar(&this.project_index(&left, left_offset.strict_add(k))?)?
                     .to_u8()?;
                 let right = this
-                    .read_scalar(
-                        &this.project_index(&right, right_offset.checked_add(k).unwrap())?,
-                    )?
+                    .read_scalar(&this.project_index(&right, right_offset.strict_add(k))?)?
                     .to_u8()?;
-                res = res.checked_add(left.abs_diff(right).into()).unwrap();
+                res = res.strict_add(left.abs_diff(right).into());
             }
             this.write_scalar(Scalar::from_u16(res), &this.project_index(&dest, j)?)?;
         }
@@ -1132,8 +1119,7 @@ fn pmulhrsw<'tcx>(
         let right = this.read_scalar(&this.project_index(&right, i)?)?.to_i16()?;
         let dest = this.project_index(&dest, i)?;
 
-        let res =
-            (i32::from(left).checked_mul(right.into()).unwrap() >> 14).checked_add(1).unwrap() >> 1;
+        let res = (i32::from(left).strict_mul(right.into()) >> 14).strict_add(1) >> 1;
 
         // The result of this operation can overflow a signed 16-bit integer.
         // When `left` and `right` are -0x8000, the result is 0x8000.
@@ -1229,7 +1215,7 @@ fn pack_generic<'tcx>(
     let (_, _, right) = split_simd_to_128bit_chunks(this, right)?;
     let (_, dest_items_per_chunk, dest) = split_simd_to_128bit_chunks(this, dest)?;
 
-    assert_eq!(dest_items_per_chunk, op_items_per_chunk.checked_mul(2).unwrap());
+    assert_eq!(dest_items_per_chunk, op_items_per_chunk.strict_mul(2));
 
     for i in 0..num_chunks {
         let left = this.project_index(&left, i)?;
@@ -1240,8 +1226,7 @@ fn pack_generic<'tcx>(
             let left = this.read_scalar(&this.project_index(&left, j)?)?;
             let right = this.read_scalar(&this.project_index(&right, j)?)?;
             let left_dest = this.project_index(&dest, j)?;
-            let right_dest =
-                this.project_index(&dest, j.checked_add(op_items_per_chunk).unwrap())?;
+            let right_dest = this.project_index(&dest, j.strict_add(op_items_per_chunk))?;
 
             let left_res = f(left)?;
             let right_res = f(right)?;
@@ -1360,3 +1345,27 @@ fn psign<'tcx>(
 
     Ok(())
 }
+
+/// Calcultates either `a + b + cb_in` or `a - b - cb_in` depending on the value
+/// of `op` and returns both the sum and the overflow bit. `op` is expected to be
+/// either one of `mir::BinOp::AddWithOverflow` and `mir::BinOp::SubWithOverflow`.
+fn carrying_add<'tcx>(
+    this: &mut crate::MiriInterpCx<'tcx>,
+    cb_in: &OpTy<'tcx>,
+    a: &OpTy<'tcx>,
+    b: &OpTy<'tcx>,
+    op: mir::BinOp,
+) -> InterpResult<'tcx, (ImmTy<'tcx>, Scalar)> {
+    assert!(op == mir::BinOp::AddWithOverflow || op == mir::BinOp::SubWithOverflow);
+
+    let cb_in = this.read_scalar(cb_in)?.to_u8()? != 0;
+    let a = this.read_immediate(a)?;
+    let b = this.read_immediate(b)?;
+
+    let (sum, overflow1) = this.binary_op(op, &a, &b)?.to_pair(this);
+    let (sum, overflow2) =
+        this.binary_op(op, &sum, &ImmTy::from_uint(cb_in, a.layout))?.to_pair(this);
+    let cb_out = overflow1.to_scalar().to_bool()? | overflow2.to_scalar().to_bool()?;
+
+    Ok((sum, Scalar::from_u8(cb_out.into())))
+}
diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs
index e10047fefe6..3efdd561d6c 100644
--- a/src/tools/miri/src/shims/x86/sse2.rs
+++ b/src/tools/miri/src/shims/x86/sse2.rs
@@ -47,22 +47,22 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let (dest, dest_len) = this.mplace_to_simd(dest)?;
 
                 assert_eq!(left_len, right_len);
-                assert_eq!(dest_len.checked_mul(2).unwrap(), left_len);
+                assert_eq!(dest_len.strict_mul(2), left_len);
 
                 for i in 0..dest_len {
-                    let j1 = i.checked_mul(2).unwrap();
+                    let j1 = i.strict_mul(2);
                     let left1 = this.read_scalar(&this.project_index(&left, j1)?)?.to_i16()?;
                     let right1 = this.read_scalar(&this.project_index(&right, j1)?)?.to_i16()?;
 
-                    let j2 = j1.checked_add(1).unwrap();
+                    let j2 = j1.strict_add(1);
                     let left2 = this.read_scalar(&this.project_index(&left, j2)?)?.to_i16()?;
                     let right2 = this.read_scalar(&this.project_index(&right, j2)?)?.to_i16()?;
 
                     let dest = this.project_index(&dest, i)?;
 
                     // Multiplications are i16*i16->i32, which will not overflow.
-                    let mul1 = i32::from(left1).checked_mul(right1.into()).unwrap();
-                    let mul2 = i32::from(left2).checked_mul(right2.into()).unwrap();
+                    let mul1 = i32::from(left1).strict_mul(right1.into());
+                    let mul2 = i32::from(left2).strict_mul(right2.into());
                     // However, this addition can overflow in the most extreme case
                     // (-0x8000)*(-0x8000)+(-0x8000)*(-0x8000) = 0x80000000
                     let res = mul1.wrapping_add(mul2);
@@ -94,14 +94,14 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     let dest = this.project_index(&dest, i)?;
 
                     let mut res: u16 = 0;
-                    let n = left_len.checked_div(dest_len).unwrap();
+                    let n = left_len.strict_div(dest_len);
                     for j in 0..n {
-                        let op_i = j.checked_add(i.checked_mul(n).unwrap()).unwrap();
+                        let op_i = j.strict_add(i.strict_mul(n));
                         let left = this.read_scalar(&this.project_index(&left, op_i)?)?.to_u8()?;
                         let right =
                             this.read_scalar(&this.project_index(&right, op_i)?)?.to_u8()?;
 
-                        res = res.checked_add(left.abs_diff(right).into()).unwrap();
+                        res = res.strict_add(left.abs_diff(right).into());
                     }
 
                     this.write_scalar(Scalar::from_u64(res.into()), &dest)?;
diff --git a/src/tools/miri/src/shims/x86/ssse3.rs b/src/tools/miri/src/shims/x86/ssse3.rs
index 6a815e4cea3..ecacaeb9af5 100644
--- a/src/tools/miri/src/shims/x86/ssse3.rs
+++ b/src/tools/miri/src/shims/x86/ssse3.rs
@@ -89,22 +89,22 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let (dest, dest_len) = this.mplace_to_simd(dest)?;
 
                 assert_eq!(left_len, right_len);
-                assert_eq!(dest_len.checked_mul(2).unwrap(), left_len);
+                assert_eq!(dest_len.strict_mul(2), left_len);
 
                 for i in 0..dest_len {
-                    let j1 = i.checked_mul(2).unwrap();
+                    let j1 = i.strict_mul(2);
                     let left1 = this.read_scalar(&this.project_index(&left, j1)?)?.to_u8()?;
                     let right1 = this.read_scalar(&this.project_index(&right, j1)?)?.to_i8()?;
 
-                    let j2 = j1.checked_add(1).unwrap();
+                    let j2 = j1.strict_add(1);
                     let left2 = this.read_scalar(&this.project_index(&left, j2)?)?.to_u8()?;
                     let right2 = this.read_scalar(&this.project_index(&right, j2)?)?.to_i8()?;
 
                     let dest = this.project_index(&dest, i)?;
 
                     // Multiplication of a u8 and an i8 into an i16 cannot overflow.
-                    let mul1 = i16::from(left1).checked_mul(right1.into()).unwrap();
-                    let mul2 = i16::from(left2).checked_mul(right2.into()).unwrap();
+                    let mul1 = i16::from(left1).strict_mul(right1.into());
+                    let mul2 = i16::from(left2).strict_mul(right2.into());
                     let res = mul1.saturating_add(mul2);
 
                     this.write_scalar(Scalar::from_i16(res), &dest)?;
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_main_terminate.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_main_terminate.stderr
index 078b7d2e0d8..9d6be16b83a 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_main_terminate.stderr
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_main_terminate.stderr
@@ -1,6 +1,6 @@
 error: the main thread terminated without waiting for all remaining threads
 
-note: pass `-Zmiri-ignore-leaks` to disable this check
+note: set `MIRIFLAGS=-Zmiri-ignore-leaks` to disable this check
 
 error: aborting due to 1 previous error
 
diff --git a/src/tools/miri/tests/fail-dep/libc/aligned_alloc_size_zero_leak.stderr b/src/tools/miri/tests/fail-dep/libc/aligned_alloc_size_zero_leak.stderr
index b0756d57212..91c67823320 100644
--- a/src/tools/miri/tests/fail-dep/libc/aligned_alloc_size_zero_leak.stderr
+++ b/src/tools/miri/tests/fail-dep/libc/aligned_alloc_size_zero_leak.stderr
@@ -9,7 +9,7 @@ LL |         aligned_alloc(2, 0);
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
-note: the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check
+note: set `MIRIFLAGS=-Zmiri-ignore-leaks` to disable this check
 
 error: aborting due to 1 previous error
 
diff --git a/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.stderr b/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.stderr
index 1d6626dda70..9abe145ea9e 100644
--- a/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.stderr
+++ b/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.stderr
@@ -4,8 +4,8 @@ error: unsupported operation: `read` from stdin not available when isolation is
 LL |         libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `read` from stdin not available when isolation is enabled
    |
-   = help: pass the flag `-Zmiri-disable-isolation` to disable isolation;
-   = help: or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning
+   = help: set `MIRIFLAGS=-Zmiri-disable-isolation` to disable isolation;
+   = help: or set `MIRIFLAGS=-Zmiri-isolation-error=warn` to make Miri return an error code from isolated operations (if supported for that operation) and continue with a warning
    = note: BACKTRACE:
    = note: inside `main` at $DIR/isolated_stdin.rs:LL:CC
 
diff --git a/src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.stderr b/src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.stderr
index 65ce0dcdcdd..657262b8d41 100644
--- a/src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.stderr
+++ b/src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.stderr
@@ -9,7 +9,7 @@ LL |         let _ptr = libc::malloc(0);
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
-note: the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check
+note: set `MIRIFLAGS=-Zmiri-ignore-leaks` to disable this check
 
 error: aborting due to 1 previous error
 
diff --git a/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_leak.stderr b/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_leak.stderr
index 7ea0fa31469..2639031f1cc 100644
--- a/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_leak.stderr
+++ b/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_leak.stderr
@@ -9,7 +9,7 @@ LL |     let _ = unsafe { libc::posix_memalign(&mut ptr, align, size) };
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
-note: the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check
+note: set `MIRIFLAGS=-Zmiri-ignore-leaks` to disable this check
 
 error: aborting due to 1 previous error
 
diff --git a/src/tools/miri/tests/fail/alloc/too_large.rs b/src/tools/miri/tests/fail/alloc/too_large.rs
new file mode 100644
index 00000000000..4e28d2401d7
--- /dev/null
+++ b/src/tools/miri/tests/fail/alloc/too_large.rs
@@ -0,0 +1,10 @@
+extern "Rust" {
+    fn __rust_alloc(size: usize, align: usize) -> *mut u8;
+}
+
+fn main() {
+    let bytes = isize::MAX as usize + 1;
+    unsafe {
+        __rust_alloc(bytes, 1); //~ERROR: larger than half the address space
+    }
+}
diff --git a/src/tools/miri/tests/fail/alloc/too_large.stderr b/src/tools/miri/tests/fail/alloc/too_large.stderr
new file mode 100644
index 00000000000..77dcf91d843
--- /dev/null
+++ b/src/tools/miri/tests/fail/alloc/too_large.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: creating an allocation larger than half the address space
+  --> $DIR/too_large.rs:LL:CC
+   |
+LL |         __rust_alloc(bytes, 1);
+   |         ^^^^^^^^^^^^^^^^^^^^^^ creating an allocation larger than half the address space
+   |
+   = 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 $DIR/too_large.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/extern-type-field-offset.stderr b/src/tools/miri/tests/fail/extern-type-field-offset.stderr
index e0d6e9ebf1d..3ed5732b4eb 100644
--- a/src/tools/miri/tests/fail/extern-type-field-offset.stderr
+++ b/src/tools/miri/tests/fail/extern-type-field-offset.stderr
@@ -1,8 +1,8 @@
-error: unsupported operation: `extern type` does not have a known offset
+error: unsupported operation: `extern type` field does not have a known offset
   --> $DIR/extern-type-field-offset.rs:LL:CC
    |
 LL |     let _field = &x.a;
-   |                  ^^^^ `extern type` does not have a known offset
+   |                  ^^^^ `extern type` field does not have a known offset
    |
    = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support
    = note: BACKTRACE:
diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind1.rs b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind1.rs
index 6d68b9a46d9..dc192d03196 100644
--- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind1.rs
+++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind1.rs
@@ -1,5 +1,3 @@
-#![feature(c_unwind)]
-
 #[no_mangle]
 extern "C-unwind" fn unwind() {
     panic!();
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 e6aff19b02d..1382e9571f3 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
@@ -4,7 +4,7 @@
 //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> ""
 //@normalize-stderr-test: "\n +at [^\n]+" -> ""
 //@[definition,both]error-in-other-file: aborted execution
-#![feature(rustc_attrs, c_unwind)]
+#![feature(rustc_attrs)]
 
 #[cfg_attr(any(definition, both), rustc_nounwind)]
 #[no_mangle]
diff --git a/src/tools/miri/tests/fail/intrinsic_fallback_is_spec.rs b/src/tools/miri/tests/fail/intrinsic_fallback_is_spec.rs
index 888c548e49b..fa7c0bf5c0c 100644
--- a/src/tools/miri/tests/fail/intrinsic_fallback_is_spec.rs
+++ b/src/tools/miri/tests/fail/intrinsic_fallback_is_spec.rs
@@ -1,4 +1,4 @@
-#![feature(rustc_attrs, effects)]
+#![feature(rustc_attrs)]
 
 #[rustc_intrinsic]
 #[rustc_nounwind]
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr
index 4e2e7218432..217bc82010d 100644
--- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr
@@ -4,12 +4,11 @@ warning: integer-to-pointer cast
 LL |         (*p.as_mut_ptr().cast::<[*const i32; 2]>())[0] = 4 as *const i32;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast
    |
-   = help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`,
-   = help: which means that Miri might miss pointer bugs in this program.
+   = help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, which means that Miri might miss pointer bugs in this program.
    = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation.
    = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead.
-   = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `with_exposed_provenance` semantics.
-   = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning.
+   = 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 $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC
 
diff --git a/src/tools/miri/tests/fail/memleak.stderr b/src/tools/miri/tests/fail/memleak.stderr
index 8ba78ef6644..a9ee76fbe8a 100644
--- a/src/tools/miri/tests/fail/memleak.stderr
+++ b/src/tools/miri/tests/fail/memleak.stderr
@@ -18,7 +18,7 @@ LL |     std::mem::forget(Box::new(42));
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
-note: the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check
+note: set `MIRIFLAGS=-Zmiri-ignore-leaks` to disable this check
 
 error: aborting due to 1 previous error
 
diff --git a/src/tools/miri/tests/fail/memleak_no_backtrace.rs b/src/tools/miri/tests/fail/memleak_no_backtrace.rs
index a1f8d9957ff..1f8d8ba7a7c 100644
--- a/src/tools/miri/tests/fail/memleak_no_backtrace.rs
+++ b/src/tools/miri/tests/fail/memleak_no_backtrace.rs
@@ -1,5 +1,5 @@
 //@compile-flags: -Zmiri-disable-leak-backtraces
-//@error-in-other-file: the evaluated program leaked memory
+//@error-in-other-file: memory leaked
 //@normalize-stderr-test: ".*│.*" -> "$$stripped$$"
 
 fn main() {
diff --git a/src/tools/miri/tests/fail/memleak_no_backtrace.stderr b/src/tools/miri/tests/fail/memleak_no_backtrace.stderr
index 22e8c558061..6850928e150 100644
--- a/src/tools/miri/tests/fail/memleak_no_backtrace.stderr
+++ b/src/tools/miri/tests/fail/memleak_no_backtrace.stderr
@@ -1,4 +1,6 @@
-error: the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check
+error: memory leaked: ALLOC (Rust heap, size: 4, align: 4)
+
+note: set `MIRIFLAGS=-Zmiri-ignore-leaks` to disable this check
 
 error: aborting due to 1 previous error
 
diff --git a/src/tools/miri/tests/fail/memleak_rc.32bit.stderr b/src/tools/miri/tests/fail/memleak_rc.32bit.stderr
deleted file mode 100644
index 781e1458db9..00000000000
--- a/src/tools/miri/tests/fail/memleak_rc.32bit.stderr
+++ /dev/null
@@ -1,25 +0,0 @@
-error: memory leaked: ALLOC (Rust heap, size: 16, align: 4), allocated here:
-  --> RUSTLIB/alloc/src/alloc.rs:LL:CC
-   |
-LL |         __rust_alloc(layout.size(), layout.align())
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: BACKTRACE:
-   = note: inside `std::alloc::alloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
-   = note: inside `std::alloc::Global::alloc_impl` at RUSTLIB/alloc/src/alloc.rs:LL:CC
-   = note: inside `<std::alloc::Global as std::alloc::Allocator>::allocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC
-   = note: inside `alloc::alloc::exchange_malloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
-   = note: inside `std::boxed::Box::<std::rc::RcBox<std::cell::RefCell<std::option::Option<Dummy>>>>::new` at RUSTLIB/alloc/src/boxed.rs:LL:CC
-   = note: inside `std::rc::Rc::<std::cell::RefCell<std::option::Option<Dummy>>>::new` at RUSTLIB/alloc/src/rc.rs:LL:CC
-note: inside `main`
-  --> $DIR/memleak_rc.rs:LL:CC
-   |
-LL |     let x = Dummy(Rc::new(RefCell::new(None)));
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-note: the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/miri/tests/fail/memleak_rc.rs b/src/tools/miri/tests/fail/memleak_rc.rs
index 0927612d08e..2d12c1223cf 100644
--- a/src/tools/miri/tests/fail/memleak_rc.rs
+++ b/src/tools/miri/tests/fail/memleak_rc.rs
@@ -1,6 +1,6 @@
 //@error-in-other-file: memory leaked
-//@stderr-per-bitwidth
 //@normalize-stderr-test: ".*│.*" -> "$$stripped$$"
+//@normalize-stderr-test: "Rust heap, size: [0-9]+, align: [0-9]+" -> "Rust heap, SIZE, ALIGN"
 
 use std::cell::RefCell;
 use std::rc::Rc;
diff --git a/src/tools/miri/tests/fail/memleak_rc.64bit.stderr b/src/tools/miri/tests/fail/memleak_rc.stderr
index 1c85a0f9d9f..dbf2daf818c 100644
--- a/src/tools/miri/tests/fail/memleak_rc.64bit.stderr
+++ b/src/tools/miri/tests/fail/memleak_rc.stderr
@@ -1,4 +1,4 @@
-error: memory leaked: ALLOC (Rust heap, size: 32, align: 8), allocated here:
+error: memory leaked: ALLOC (Rust heap, SIZE, ALIGN), allocated here:
   --> RUSTLIB/alloc/src/alloc.rs:LL:CC
    |
 LL |         __rust_alloc(layout.size(), layout.align())
@@ -19,7 +19,7 @@ LL |     let x = Dummy(Rc::new(RefCell::new(None)));
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
-note: the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check
+note: set `MIRIFLAGS=-Zmiri-ignore-leaks` to disable this check
 
 error: aborting due to 1 previous error
 
diff --git a/src/tools/miri/tests/fail/panic/bad_unwind.rs b/src/tools/miri/tests/fail/panic/bad_unwind.rs
index 8c8a9f18cdc..5370485b2a6 100644
--- a/src/tools/miri/tests/fail/panic/bad_unwind.rs
+++ b/src/tools/miri/tests/fail/panic/bad_unwind.rs
@@ -1,5 +1,3 @@
-#![feature(c_unwind)]
-
 //! Unwinding when the caller ABI is "C" (without "-unwind") is UB.
 // The opposite version (callee does not allow unwinding) is impossible to
 // even write: MIR validation catches functions that have `UnwindContinue` but
diff --git a/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr b/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr
index 1f08649428a..ec956f83348 100644
--- a/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr
+++ b/src/tools/miri/tests/fail/shims/fs/isolated_file.stderr
@@ -4,8 +4,8 @@ error: unsupported operation: `open` not available when isolation is enabled
 LL |         let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode as c_int) })?;
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `open` not available when isolation is enabled
    |
-   = help: pass the flag `-Zmiri-disable-isolation` to disable isolation;
-   = help: or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning
+   = help: set `MIRIFLAGS=-Zmiri-disable-isolation` to disable isolation;
+   = help: or set `MIRIFLAGS=-Zmiri-isolation-error=warn` to make Miri return an error code from isolated operations (if supported for that operation) and continue with a warning
    = note: BACKTRACE:
    = note: inside closure at RUSTLIB/std/src/sys/pal/PLATFORM/fs.rs:LL:CC
    = note: inside `std::sys::pal::PLATFORM::cvt_r::<i32, {closure@std::sys::pal::PLATFORM::fs::File::open_c::{closure#0}}>` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/tail_calls/cc-mismatch.rs b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.rs
new file mode 100644
index 00000000000..5f00dbf2573
--- /dev/null
+++ b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.rs
@@ -0,0 +1,10 @@
+//@error-in-other-file: Undefined Behavior: calling a function with calling convention C using calling convention Rust
+#![feature(explicit_tail_calls)]
+#![allow(incomplete_features)]
+
+fn main() {
+    let f = unsafe { std::mem::transmute::<extern "C" fn(), fn()>(f) };
+    become f();
+}
+
+extern "C" fn f() {}
diff --git a/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr
new file mode 100644
index 00000000000..b157e9f0b21
--- /dev/null
+++ b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr
@@ -0,0 +1,25 @@
+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
+   |
+   = 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 `<fn() as std::ops::FnOnce<()>>::call_once - shim(fn())` at RUSTLIB/core/src/ops/function.rs:LL:CC
+   = note: inside `std::sys::backtrace::__rust_begin_short_backtrace::<fn(), ()>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
+   = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC
+   = note: inside `std::ops::function::impls::<impl std::ops::FnOnce<()> for &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>::call_once` at RUSTLIB/core/src/ops/function.rs:LL:CC
+   = note: inside `std::panicking::r#try::do_call::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` at RUSTLIB/std/src/panicking.rs:LL:CC
+   = note: inside `std::panicking::r#try::<i32, &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>` at RUSTLIB/std/src/panicking.rs:LL:CC
+   = note: inside `std::panic::catch_unwind::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` at RUSTLIB/std/src/panic.rs:LL:CC
+   = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC
+   = note: inside `std::panicking::r#try::do_call::<{closure@std::rt::lang_start_internal::{closure#2}}, isize>` at RUSTLIB/std/src/panicking.rs:LL:CC
+   = note: inside `std::panicking::r#try::<isize, {closure@std::rt::lang_start_internal::{closure#2}}>` at RUSTLIB/std/src/panicking.rs:LL:CC
+   = note: inside `std::panic::catch_unwind::<{closure@std::rt::lang_start_internal::{closure#2}}, isize>` at RUSTLIB/std/src/panic.rs:LL:CC
+   = note: inside `std::rt::lang_start_internal` at RUSTLIB/std/src/rt.rs:LL:CC
+   = note: inside `std::rt::lang_start::<()>` at RUSTLIB/std/src/rt.rs:LL:CC
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs
new file mode 100644
index 00000000000..6df132d3255
--- /dev/null
+++ b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs
@@ -0,0 +1,17 @@
+#![feature(explicit_tail_calls)]
+#![allow(incomplete_features)]
+
+fn main() {
+    // FIXME(explicit_tail_calls):
+    //   the error should point to `become g(x)`,
+    //   but tail calls mess up the backtrace it seems like...
+    f(0);
+    //~^ error: Undefined Behavior: calling a function with argument of type i32 passing data of type u32
+}
+
+fn f(x: u32) {
+    let g = unsafe { std::mem::transmute::<fn(i32), fn(u32)>(g) };
+    become g(x);
+}
+
+fn g(_: i32) {}
diff --git a/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr
new file mode 100644
index 00000000000..8823ab9b970
--- /dev/null
+++ b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr
@@ -0,0 +1,17 @@
+error: Undefined Behavior: calling a function with argument of type i32 passing data of type u32
+  --> $DIR/signature-mismatch-arg.rs:LL:CC
+   |
+LL |     f(0);
+   |     ^^^^ calling a function with argument of type i32 passing data of type u32
+   |
+   = 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
+   = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
+   = help: if you think this code should be accepted anyway, please report an issue with Miri
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/signature-mismatch-arg.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/terminate-terminator.rs b/src/tools/miri/tests/fail/terminate-terminator.rs
index 7c672828030..465625c7572 100644
--- a/src/tools/miri/tests/fail/terminate-terminator.rs
+++ b/src/tools/miri/tests/fail/terminate-terminator.rs
@@ -7,8 +7,6 @@
 // Enable MIR inlining to ensure that `TerminatorKind::UnwindTerminate` is generated
 // instead of just `UnwindAction::Terminate`.
 
-#![feature(c_unwind)]
-
 struct Foo;
 
 impl Drop for Foo {
diff --git a/src/tools/miri/tests/fail/tls_macro_leak.stderr b/src/tools/miri/tests/fail/tls_macro_leak.stderr
index 40b21f8625a..c7c641a30f1 100644
--- a/src/tools/miri/tests/fail/tls_macro_leak.stderr
+++ b/src/tools/miri/tests/fail/tls_macro_leak.stderr
@@ -27,7 +27,7 @@ LL | |         });
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
-note: the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check
+note: set `MIRIFLAGS=-Zmiri-ignore-leaks` to disable this check
 
 error: aborting due to 1 previous error
 
diff --git a/src/tools/miri/tests/fail/tls_static_leak.stderr b/src/tools/miri/tests/fail/tls_static_leak.stderr
index 580b52c1512..f7b90a1118c 100644
--- a/src/tools/miri/tests/fail/tls_static_leak.stderr
+++ b/src/tools/miri/tests/fail/tls_static_leak.stderr
@@ -18,7 +18,7 @@ LL |         TLS.set(Some(Box::leak(Box::new(123))));
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
-note: the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check
+note: set `MIRIFLAGS=-Zmiri-ignore-leaks` to disable this check
 
 error: aborting due to 1 previous error
 
diff --git a/src/tools/miri/tests/fail/tree_borrows/protector-write-lazy.rs b/src/tools/miri/tests/fail/tree_borrows/protector-write-lazy.rs
new file mode 100644
index 00000000000..238f6dba9d3
--- /dev/null
+++ b/src/tools/miri/tests/fail/tree_borrows/protector-write-lazy.rs
@@ -0,0 +1,35 @@
+//@compile-flags: -Zmiri-tree-borrows
+// This test tests that TB's protector end semantics correctly ensure
+// that protected activated writes can be reordered.
+fn the_other_function(ref_to_fst_elem: &mut i32, ptr_to_vec: *mut i32) -> *mut i32 {
+    // Activate the reference. Afterwards, we should be able to reorder arbitrary writes.
+    *ref_to_fst_elem = 0;
+    // Here is such an arbitrary write.
+    // It could be moved down after the retag, in which case the `funky_ref` would be invalidated.
+    // We need to ensure that the `funky_ptr` is unusable even if the write to `ref_to_fst_elem`
+    // happens before the retag.
+    *ref_to_fst_elem = 42;
+    // this creates a reference that is Reserved Lazy on the first element (offset 0).
+    // It does so by doing a proper retag on the second element (offset 1), which is fine
+    // since nothing else happens at that offset, but the lazy init mechanism means it's
+    // also reserved at offset 0, but not initialized.
+    let funky_ptr_lazy_on_fst_elem =
+        unsafe { (&mut *(ptr_to_vec.wrapping_add(1))) as *mut i32 }.wrapping_sub(1);
+    // If we write to `ref_to_fst_elem` here, then any further access to `funky_ptr_lazy_on_fst_elem` would
+    // definitely be UB. Since the compiler ought to be able to reorder the write of `42` above down to
+    // here, that means we want this program to also be UB.
+    return funky_ptr_lazy_on_fst_elem;
+}
+
+fn main() {
+    let mut v = vec![0, 1];
+    // get a pointer to the root of the allocation
+    // note that it's not important it's the actual root, what matters is that it's a parent
+    // of both references that will be created
+    let ptr_to_vec = v.as_mut_ptr();
+    let ref_to_fst_elem = unsafe { &mut *ptr_to_vec };
+    let funky_ptr_lazy_on_fst_elem = the_other_function(ref_to_fst_elem, ptr_to_vec);
+    // now we try to use the funky lazy pointer.
+    // It should be UB, since the write-on-protector-end should disable it.
+    unsafe { println!("Value of funky: {}", *funky_ptr_lazy_on_fst_elem) } //~ ERROR: /reborrow through .* is forbidden/
+}
diff --git a/src/tools/miri/tests/fail/tree_borrows/protector-write-lazy.stderr b/src/tools/miri/tests/fail/tree_borrows/protector-write-lazy.stderr
new file mode 100644
index 00000000000..955abd144c7
--- /dev/null
+++ b/src/tools/miri/tests/fail/tree_borrows/protector-write-lazy.stderr
@@ -0,0 +1,27 @@
+error: Undefined Behavior: reborrow through <TAG> at ALLOC[0x0] is forbidden
+  --> $DIR/protector-write-lazy.rs:LL:CC
+   |
+LL |     unsafe { println!("Value of funky: {}", *funky_ptr_lazy_on_fst_elem) }
+   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ reborrow 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 reborrow (acting as a child read access)
+help: the accessed tag <TAG> was created here, in the initial state Reserved
+  --> $DIR/protector-write-lazy.rs:LL:CC
+   |
+LL |         unsafe { (&mut *(ptr_to_vec.wrapping_add(1))) as *mut i32 }.wrapping_sub(1);
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: the accessed tag <TAG> later transitioned to Disabled due to a protector release (acting as a foreign write access) on every location previously accessed by this tag
+  --> $DIR/protector-write-lazy.rs:LL:CC
+   |
+LL | }
+   |  ^
+   = help: this transition corresponds to a loss of read and write permissions
+   = note: BACKTRACE (of the first span):
+   = note: inside `main` at $DIR/protector-write-lazy.rs:LL:CC
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+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 86406872c59..465e07c8db4 100644
--- a/src/tools/miri/tests/fail/unwind-action-terminate.rs
+++ b/src/tools/miri/tests/fail/unwind-action-terminate.rs
@@ -3,8 +3,6 @@
 //@normalize-stderr-test: "\| +\^+" -> "| ^"
 //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> ""
 //@normalize-stderr-test: "\n +at [^\n]+" -> ""
-#![feature(c_unwind)]
-
 extern "C" fn panic_abort() {
     panic!()
 }
diff --git a/src/tools/miri/tests/panic/function_calls/exported_symbol_good_unwind.rs b/src/tools/miri/tests/panic/function_calls/exported_symbol_good_unwind.rs
index 71b799a1f12..0e8d45af27f 100644
--- a/src/tools/miri/tests/panic/function_calls/exported_symbol_good_unwind.rs
+++ b/src/tools/miri/tests/panic/function_calls/exported_symbol_good_unwind.rs
@@ -2,7 +2,7 @@
 // found in this form" errors works without `-C prefer-dynamic` (`panic!` calls foreign function
 // `__rust_start_panic`).
 // no-prefer-dynamic
-#![feature(c_unwind, unboxed_closures)]
+#![feature(unboxed_closures)]
 
 use std::panic;
 
diff --git a/src/tools/miri/tests/pass-dep/concurrency/tls_pthread_drop_order.rs b/src/tools/miri/tests/pass-dep/concurrency/tls_pthread_drop_order.rs
index 0eaab967642..52348aad33d 100644
--- a/src/tools/miri/tests/pass-dep/concurrency/tls_pthread_drop_order.rs
+++ b/src/tools/miri/tests/pass-dep/concurrency/tls_pthread_drop_order.rs
@@ -1,9 +1,9 @@
 //@ignore-target-windows: No pthreads on Windows
 //! Test that pthread_key destructors are run in the right order.
 //! Note that these are *not* used by actual `thread_local!` on Linux! Those use
-//! `thread_local_dtor::register_dtor` from the stdlib instead. In Miri this hits the fallback path
-//! in `register_dtor_fallback`, which uses a *single* pthread_key to manage a thread-local list of
-//! dtors to call.
+//! `destructors::register` from the stdlib instead. In Miri this ends up hitting
+//! the fallback path in `guard::key::enable`, which uses a *single* pthread_key
+//! to manage a thread-local list of dtors to call.
 
 use std::mem;
 use std::ptr;
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs
index 80c9757e9c9..da685e5c6b7 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs
@@ -15,6 +15,7 @@ use std::path::PathBuf;
 mod utils;
 
 fn main() {
+    test_dup();
     test_dup_stdout_stderr();
     test_canonicalize_too_long();
     test_rename();
@@ -74,6 +75,31 @@ fn test_dup_stdout_stderr() {
     }
 }
 
+fn test_dup() {
+    let bytes = b"dup and dup2";
+    let path = utils::prepare_with_content("miri_test_libc_dup.txt", bytes);
+
+    let mut name = path.into_os_string();
+    name.push("\0");
+    let name_ptr = name.as_bytes().as_ptr().cast::<libc::c_char>();
+    unsafe {
+        let fd = libc::open(name_ptr, libc::O_RDONLY);
+        let mut first_buf = [0u8; 4];
+        libc::read(fd, first_buf.as_mut_ptr() as *mut libc::c_void, 4);
+        assert_eq!(&first_buf, b"dup ");
+
+        let new_fd = libc::dup(fd);
+        let mut second_buf = [0u8; 4];
+        libc::read(new_fd, second_buf.as_mut_ptr() as *mut libc::c_void, 4);
+        assert_eq!(&second_buf, b"and ");
+
+        let new_fd2 = libc::dup2(fd, 8);
+        let mut third_buf = [0u8; 4];
+        libc::read(new_fd2, third_buf.as_mut_ptr() as *mut libc::c_void, 4);
+        assert_eq!(&third_buf, b"dup2");
+    }
+}
+
 fn test_canonicalize_too_long() {
     // Make sure we get an error for long paths.
     let too_long = "x/".repeat(libc::PATH_MAX.try_into().unwrap());
diff --git a/src/tools/miri/tests/pass/async-closure.rs b/src/tools/miri/tests/pass/async-closure.rs
index 2f7ec2b9e6f..721af578883 100644
--- a/src/tools/miri/tests/pass/async-closure.rs
+++ b/src/tools/miri/tests/pass/async-closure.rs
@@ -1,7 +1,8 @@
 #![feature(async_closure, noop_waker, async_fn_traits)]
+#![allow(unused)]
 
 use std::future::Future;
-use std::ops::{AsyncFnMut, AsyncFnOnce};
+use std::ops::{AsyncFn, AsyncFnMut, AsyncFnOnce};
 use std::pin::pin;
 use std::task::*;
 
@@ -17,6 +18,10 @@ pub fn block_on<T>(fut: impl Future<Output = T>) -> T {
     }
 }
 
+async fn call(f: &mut impl AsyncFn(i32)) {
+    f(0).await;
+}
+
 async fn call_mut(f: &mut impl AsyncFnMut(i32)) {
     f(0).await;
 }
@@ -26,10 +31,10 @@ async fn call_once(f: impl AsyncFnOnce(i32)) {
 }
 
 async fn call_normal<F: Future<Output = ()>>(f: &impl Fn(i32) -> F) {
-    f(0).await;
+    f(1).await;
 }
 
-async fn call_normal_once<F: Future<Output = ()>>(f: impl FnOnce(i32) -> F) {
+async fn call_normal_mut<F: Future<Output = ()>>(f: &mut impl FnMut(i32) -> F) {
     f(1).await;
 }
 
@@ -39,14 +44,16 @@ pub fn main() {
         let mut async_closure = async move |a: i32| {
             println!("{a} {b}");
         };
+        call(&mut async_closure).await;
         call_mut(&mut async_closure).await;
         call_once(async_closure).await;
 
-        // No-capture closures implement `Fn`.
-        let async_closure = async move |a: i32| {
-            println!("{a}");
+        let b = 2i32;
+        let mut async_closure = async |a: i32| {
+            println!("{a} {b}");
         };
         call_normal(&async_closure).await;
-        call_normal_once(async_closure).await;
+        call_normal_mut(&mut async_closure).await;
+        call_once(async_closure).await;
     });
 }
diff --git a/src/tools/miri/tests/pass/async-closure.stdout b/src/tools/miri/tests/pass/async-closure.stdout
index 7baae1aa94f..217944c84a2 100644
--- a/src/tools/miri/tests/pass/async-closure.stdout
+++ b/src/tools/miri/tests/pass/async-closure.stdout
@@ -1,4 +1,6 @@
 0 2
+0 2
+1 2
+1 2
+1 2
 1 2
-0
-1
diff --git a/src/tools/miri/tests/pass/box.stack.stderr b/src/tools/miri/tests/pass/box.stack.stderr
index 1a4d52ee314..341f84c8992 100644
--- a/src/tools/miri/tests/pass/box.stack.stderr
+++ b/src/tools/miri/tests/pass/box.stack.stderr
@@ -4,12 +4,11 @@ warning: integer-to-pointer cast
 LL |         let r2 = ((r as usize) + 0) as *mut i32;
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast
    |
-   = help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`,
-   = help: which means that Miri might miss pointer bugs in this program.
+   = help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, which means that Miri might miss pointer bugs in this program.
    = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation.
    = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead.
-   = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `with_exposed_provenance` semantics.
-   = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning.
+   = 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 `into_raw` at $DIR/box.rs:LL:CC
 note: inside `main`
diff --git a/src/tools/miri/tests/pass/extern_types.stack.stderr b/src/tools/miri/tests/pass/extern_types.stack.stderr
index 275d718129b..03a9167abbc 100644
--- a/src/tools/miri/tests/pass/extern_types.stack.stderr
+++ b/src/tools/miri/tests/pass/extern_types.stack.stderr
@@ -4,12 +4,11 @@ warning: integer-to-pointer cast
 LL |     let x: &Foo = unsafe { &*(16 as *const Foo) };
    |                              ^^^^^^^^^^^^^^^^^^ integer-to-pointer cast
    |
-   = help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`,
-   = help: which means that Miri might miss pointer bugs in this program.
+   = help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, which means that Miri might miss pointer bugs in this program.
    = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation.
    = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead.
-   = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `with_exposed_provenance` semantics.
-   = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning.
+   = 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 $DIR/extern_types.rs:LL:CC
 
diff --git a/src/tools/miri/tests/pass/function_pointers.rs b/src/tools/miri/tests/pass/function_pointers.rs
index 36679b7180a..2aa3ebf2dd0 100644
--- a/src/tools/miri/tests/pass/function_pointers.rs
+++ b/src/tools/miri/tests/pass/function_pointers.rs
@@ -23,6 +23,7 @@ fn h(i: i32, j: i32) -> i32 {
     j * i * 7
 }
 
+#[inline(never)]
 fn i() -> i32 {
     73
 }
@@ -77,7 +78,7 @@ fn main() {
     assert_eq!(indirect_mut3(h), 210);
     assert_eq!(indirect_once3(h), 210);
     // Check that `i` always has the same address. This is not guaranteed
-    // but Miri currently uses a fixed address for monomorphic functions.
+    // but Miri currently uses a fixed address for non-inlineable monomorphic functions.
     assert!(return_fn_ptr(i) == i);
     assert!(return_fn_ptr(i) as unsafe fn() -> i32 == i as fn() -> i32 as unsafe fn() -> i32);
     // Miri gives different addresses to different reifications of a generic function.
diff --git a/src/tools/miri/tests/pass/intptrcast.rs b/src/tools/miri/tests/pass/intptrcast.rs
index 4e9fa12c181..fb1a1dfae5d 100644
--- a/src/tools/miri/tests/pass/intptrcast.rs
+++ b/src/tools/miri/tests/pass/intptrcast.rs
@@ -35,7 +35,7 @@ fn cast_dangling() {
 fn format() {
     // Pointer string formatting! We can't check the output as it changes when libstd changes,
     // but we can make sure Miri does not error.
-    format!("{:?}", &mut 13 as *mut _);
+    let _ = format!("{:?}", &mut 13 as *mut _);
 }
 
 fn transmute() {
@@ -52,7 +52,7 @@ fn ptr_bitops1() {
     let one = bytes.as_ptr().wrapping_offset(1);
     let three = bytes.as_ptr().wrapping_offset(3);
     let res = (one as usize) | (three as usize);
-    format!("{}", res);
+    let _ = format!("{}", res);
 }
 
 fn ptr_bitops2() {
diff --git a/src/tools/miri/tests/pass/issues/issue-91636.rs b/src/tools/miri/tests/pass/issues/issue-91636.rs
index 21000bb68d2..00370165812 100644
--- a/src/tools/miri/tests/pass/issues/issue-91636.rs
+++ b/src/tools/miri/tests/pass/issues/issue-91636.rs
@@ -10,6 +10,7 @@ impl Function {
     }
 }
 
+#[inline(never)]
 fn dummy(_: &str) {}
 
 fn main() {
diff --git a/src/tools/miri/tests/pass/issues/issue-miri-3680.rs b/src/tools/miri/tests/pass/issues/issue-miri-3680.rs
new file mode 100644
index 00000000000..55b896c91ad
--- /dev/null
+++ b/src/tools/miri/tests/pass/issues/issue-miri-3680.rs
@@ -0,0 +1,21 @@
+//@ignore-target-windows: File handling is not implemented yet
+//@compile-flags: -Zmiri-disable-isolation
+
+use std::fs::remove_file;
+use std::io::{ErrorKind, Seek};
+
+#[path = "../../utils/mod.rs"]
+mod utils;
+
+fn main() {
+    let path = utils::prepare("miri_test_fs_seek_i64_max_plus_1.txt");
+
+    let mut f = std::fs::File::create(&path).unwrap();
+    let error = f.seek(std::io::SeekFrom::Start(i64::MAX as u64 + 1)).unwrap_err();
+
+    // It should be error due to negative offset.
+    assert_eq!(error.kind(), ErrorKind::InvalidInput);
+
+    // Cleanup
+    remove_file(&path).unwrap();
+}
diff --git a/src/tools/miri/tests/pass/packed_struct.rs b/src/tools/miri/tests/pass/packed_struct.rs
index b86235e0c67..039eb5adef0 100644
--- a/src/tools/miri/tests/pass/packed_struct.rs
+++ b/src/tools/miri/tests/pass/packed_struct.rs
@@ -138,7 +138,7 @@ fn test_derive() {
     assert_eq!(x.partial_cmp(&y).unwrap(), x.cmp(&y));
     x.hash(&mut DefaultHasher::new());
     P::default();
-    format!("{:?}", x);
+    let _ = format!("{:?}", x);
 }
 
 fn main() {
diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs
index 35980fad15d..16d3e8cab30 100644
--- a/src/tools/miri/tests/pass/shims/fs.rs
+++ b/src/tools/miri/tests/pass/shims/fs.rs
@@ -202,7 +202,7 @@ fn test_errors() {
     // Opening a non-existing file should fail with a "not found" error.
     assert_eq!(ErrorKind::NotFound, File::open(&path).unwrap_err().kind());
     // Make sure we can also format this.
-    format!("{0}: {0:?}", File::open(&path).unwrap_err());
+    let _ = format!("{0}: {0:?}", File::open(&path).unwrap_err());
     // Removing a non-existing file should fail with a "not found" error.
     assert_eq!(ErrorKind::NotFound, remove_file(&path).unwrap_err().kind());
     // Reading the metadata of a non-existing file should fail with a "not found" error.
@@ -301,5 +301,5 @@ fn test_from_raw_os_error() {
     let error = Error::from_raw_os_error(code);
     assert!(matches!(error.kind(), ErrorKind::Uncategorized));
     // Make sure we can also format this.
-    format!("{error:?}");
+    let _ = format!("{error:?}");
 }
diff --git a/src/tools/miri/tests/pass/shims/io.rs b/src/tools/miri/tests/pass/shims/io.rs
index d20fc75b793..420ef95a0cb 100644
--- a/src/tools/miri/tests/pass/shims/io.rs
+++ b/src/tools/miri/tests/pass/shims/io.rs
@@ -15,5 +15,5 @@ fn main() {
         panic!("unsupported OS")
     };
     let err = io::Error::from_raw_os_error(raw_os_error);
-    format!("{err}: {err:?}");
+    let _ = format!("{err}: {err:?}");
 }
diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-adx.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-adx.rs
new file mode 100644
index 00000000000..431e7f2c5eb
--- /dev/null
+++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-adx.rs
@@ -0,0 +1,70 @@
+// Ignore everything except x86 and x86_64
+// Any new targets that are added to CI should be ignored here.
+// (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.)
+//@ignore-target-aarch64
+//@ignore-target-arm
+//@ignore-target-avr
+//@ignore-target-s390x
+//@ignore-target-thumbv7em
+//@ignore-target-wasm32
+//@compile-flags: -C target-feature=+adx
+
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+mod x86 {
+    #[cfg(target_arch = "x86")]
+    use core::arch::x86 as arch;
+    #[cfg(target_arch = "x86_64")]
+    use core::arch::x86_64 as arch;
+
+    fn adc(c_in: u8, a: u32, b: u32) -> (u8, u32) {
+        let mut sum = 0;
+        // SAFETY: There are no safety requirements for calling `_addcarry_u32`.
+        // It's just unsafe for API consistency with other intrinsics.
+        let c_out = unsafe { arch::_addcarryx_u32(c_in, a, b, &mut sum) };
+        (c_out, sum)
+    }
+
+    pub fn main() {
+        assert_eq!(adc(0, 1, 1), (0, 2));
+        assert_eq!(adc(1, 1, 1), (0, 3));
+        assert_eq!(adc(2, 1, 1), (0, 3)); // any non-zero carry acts as 1!
+        assert_eq!(adc(u8::MAX, 1, 1), (0, 3));
+        assert_eq!(adc(0, u32::MAX, u32::MAX), (1, u32::MAX - 1));
+        assert_eq!(adc(1, u32::MAX, u32::MAX), (1, u32::MAX));
+        assert_eq!(adc(2, u32::MAX, u32::MAX), (1, u32::MAX));
+        assert_eq!(adc(u8::MAX, u32::MAX, u32::MAX), (1, u32::MAX));
+    }
+}
+
+#[cfg(target_arch = "x86_64")]
+mod x86_64 {
+    use core::arch::x86_64 as arch;
+
+    fn adc(c_in: u8, a: u64, b: u64) -> (u8, u64) {
+        let mut sum = 0;
+        // SAFETY: There are no safety requirements for calling `_addcarry_u64`.
+        // It's just unsafe for API consistency with other intrinsics.
+        let c_out = unsafe { arch::_addcarryx_u64(c_in, a, b, &mut sum) };
+        (c_out, sum)
+    }
+
+    pub fn main() {
+        assert_eq!(adc(0, 1, 1), (0, 2));
+        assert_eq!(adc(1, 1, 1), (0, 3));
+        assert_eq!(adc(2, 1, 1), (0, 3)); // any non-zero carry acts as 1!
+        assert_eq!(adc(u8::MAX, 1, 1), (0, 3));
+        assert_eq!(adc(0, u64::MAX, u64::MAX), (1, u64::MAX - 1));
+        assert_eq!(adc(1, u64::MAX, u64::MAX), (1, u64::MAX));
+        assert_eq!(adc(2, u64::MAX, u64::MAX), (1, u64::MAX));
+        assert_eq!(adc(u8::MAX, u64::MAX, u64::MAX), (1, u64::MAX));
+    }
+}
+
+fn main() {
+    assert!(is_x86_feature_detected!("adx"));
+
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    x86::main();
+    #[cfg(target_arch = "x86_64")]
+    x86_64::main();
+}
diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs
index 7d43cc596ae..728f57d48f1 100644
--- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs
+++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs
@@ -1342,6 +1342,11 @@ unsafe fn test_avx() {
         assert_eq!(r, 1);
     }
     test_mm_testnzc_ps();
+
+    // These intrinsics are functionally no-ops. The only thing
+    // that needs to be tested is that they can be executed.
+    _mm256_zeroupper();
+    _mm256_zeroall();
 }
 
 #[target_feature(enable = "sse2")]
diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-bmi.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-bmi.rs
new file mode 100644
index 00000000000..33424117c45
--- /dev/null
+++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-bmi.rs
@@ -0,0 +1,216 @@
+// Ignore everything except x86 and x86_64
+// Any new targets that are added to CI should be ignored here.
+// (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.)
+//@ignore-target-aarch64
+//@ignore-target-arm
+//@ignore-target-avr
+//@ignore-target-s390x
+//@ignore-target-thumbv7em
+//@ignore-target-wasm32
+//@compile-flags: -C target-feature=+bmi1,+bmi2
+
+#[cfg(target_arch = "x86")]
+use std::arch::x86::*;
+#[cfg(target_arch = "x86_64")]
+use std::arch::x86_64::*;
+
+fn main() {
+    // BMI1 and BMI2 are independent from each other, so both must be checked.
+    assert!(is_x86_feature_detected!("bmi1"));
+    assert!(is_x86_feature_detected!("bmi2"));
+
+    unsafe {
+        test_bmi_32();
+        test_bmi_64();
+    }
+}
+
+/// Test the 32-bit variants of the intrinsics.
+unsafe fn test_bmi_32() {
+    unsafe fn test_bextr_u32() {
+        let r = _bextr_u32(0b0101_0000u32, 4, 4);
+        assert_eq!(r, 0b0000_0101u32);
+
+        for i in 0..16 {
+            assert_eq!(_bextr_u32(u32::MAX, i, 4), 0b1111);
+            assert_eq!(_bextr_u32(u32::MAX, 4, i), (1 << i) - 1);
+        }
+
+        // Ensure that indices larger than the bit count are covered.
+        // It is important to go above 32 in order to verify the bit selection
+        // of the instruction.
+
+        for i in 0..256 {
+            // If the index is out of bounds, the original input won't be changed, thus the `min(32)`.
+            assert_eq!(_bextr_u32(u32::MAX, 0, i).count_ones(), i.min(32));
+        }
+
+        for i in 0..256 {
+            assert_eq!(_bextr_u32(u32::MAX, i, 0), 0);
+        }
+
+        // Test cases with completly random values. These cases also test
+        // that the function works even if upper bits of the control value are set.
+        assert_eq!(_bextr2_u32(0x7408a392, 0x54ef705), 0x3a0451c);
+        assert_eq!(_bextr2_u32(0xbc5a3494, 0xdd193203), 0x178b4692);
+        assert_eq!(_bextr2_u32(0xc0332325, 0xf96e207), 0x1806646);
+    }
+    test_bextr_u32();
+
+    unsafe fn test_pext_u32() {
+        let n = 0b1011_1110_1001_0011u32;
+
+        let m0 = 0b0110_0011_1000_0101u32;
+        let s0 = 0b0000_0000_0011_0101u32;
+
+        let m1 = 0b1110_1011_1110_1111u32;
+        let s1 = 0b0001_0111_0100_0011u32;
+
+        // Testing of random values.
+        assert_eq!(_pext_u32(n, m0), s0);
+        assert_eq!(_pext_u32(n, m1), s1);
+        assert_eq!(_pext_u32(0x12345678, 0xff00fff0), 0x00012567);
+
+        // Testing of various identities.
+        assert_eq!(_pext_u32(u32::MAX, u32::MAX), u32::MAX);
+        assert_eq!(_pext_u32(u32::MAX, 0), 0);
+        assert_eq!(_pext_u32(0, u32::MAX), 0);
+    }
+    test_pext_u32();
+
+    unsafe fn test_pdep_u32() {
+        let n = 0b1011_1110_1001_0011u32;
+
+        let m0 = 0b0110_0011_1000_0101u32;
+        let s0 = 0b0000_0010_0000_0101u32;
+
+        let m1 = 0b1110_1011_1110_1111u32;
+        let s1 = 0b1110_1001_0010_0011u32;
+
+        // Testing of random values.
+        assert_eq!(_pdep_u32(n, m0), s0);
+        assert_eq!(_pdep_u32(n, m1), s1);
+        assert_eq!(_pdep_u32(0x00012567, 0xff00fff0), 0x12005670);
+
+        // Testing of various identities.
+        assert_eq!(_pdep_u32(u32::MAX, u32::MAX), u32::MAX);
+        assert_eq!(_pdep_u32(0, u32::MAX), 0);
+        assert_eq!(_pdep_u32(u32::MAX, 0), 0);
+    }
+    test_pdep_u32();
+
+    unsafe fn test_bzhi_u32() {
+        let n = 0b1111_0010u32;
+        let s = 0b0001_0010u32;
+        assert_eq!(_bzhi_u32(n, 5), s);
+
+        // Ensure that indices larger than the bit count are covered.
+        // It is important to go above 32 in order to verify the bit selection
+        // of the instruction.
+        for i in 0..=512 {
+            // The instruction only takes the lowest eight bits to generate the index, hence `i & 0xff`.
+            // If the index is out of bounds, the original input won't be changed, thus the `min(32)`.
+            let expected = 1u32.checked_shl((i & 0xff).min(32)).unwrap_or(0).wrapping_sub(1);
+            let actual = _bzhi_u32(u32::MAX, i);
+            assert_eq!(expected, actual);
+        }
+    }
+    test_bzhi_u32();
+}
+
+#[cfg(not(target_arch = "x86_64"))]
+unsafe fn test_bmi_64() {}
+
+/// Test the 64-bit variants of the intrinsics.
+#[cfg(target_arch = "x86_64")]
+unsafe fn test_bmi_64() {
+    unsafe fn test_bextr_u64() {
+        let r = _bextr_u64(0b0101_0000u64, 4, 4);
+        assert_eq!(r, 0b0000_0101u64);
+
+        for i in 0..16 {
+            assert_eq!(_bextr_u64(u64::MAX, i, 4), 0b1111);
+            assert_eq!(_bextr_u64(u64::MAX, 32, i), (1 << i) - 1);
+        }
+
+        // Ensure that indices larger than the bit count are covered.
+        // It is important to go above 64 in order to verify the bit selection
+        // of the instruction.
+
+        for i in 0..256 {
+            // If the index is out of bounds, the original input won't be changed, thus the `min(64)`.
+            assert_eq!(_bextr_u64(u64::MAX, 0, i).count_ones(), i.min(64));
+        }
+
+        for i in 0..256 {
+            assert_eq!(_bextr_u64(u64::MAX, i, 0), 0);
+        }
+
+        // Test cases with completly random values. These cases also test
+        // that the function works even if upper bits of the control value are set.
+        assert_eq!(_bextr2_u64(0x4ff6cfbcea75f055, 0x216642e228425719), 0x27fb67de75);
+        assert_eq!(_bextr2_u64(0xb05e991e6f6e1b6, 0xc76dd5d7f67dfc14), 0xb05e991e6f);
+        assert_eq!(_bextr2_u64(0x5a3a629e323d848f, 0x95ac507d20e7719), 0x2d1d314f19);
+    }
+    test_bextr_u64();
+
+    unsafe fn test_pext_u64() {
+        let n = 0b1011_1110_1001_0011u64;
+
+        let m0 = 0b0110_0011_1000_0101u64;
+        let s0 = 0b0000_0000_0011_0101u64;
+
+        let m1 = 0b1110_1011_1110_1111u64;
+        let s1 = 0b0001_0111_0100_0011u64;
+
+        // Testing of random values.
+        assert_eq!(_pext_u64(n, m0), s0);
+        assert_eq!(_pext_u64(n, m1), s1);
+        assert_eq!(_pext_u64(0x12345678, 0xff00fff0), 0x00012567);
+
+        // Testing of various identities.
+        assert_eq!(_pext_u64(u64::MAX, u64::MAX), u64::MAX);
+        assert_eq!(_pext_u64(u64::MAX, 0), 0);
+        assert_eq!(_pext_u64(0, u64::MAX), 0);
+    }
+    test_pext_u64();
+
+    unsafe fn test_pdep_u64() {
+        let n = 0b1011_1110_1001_0011u64;
+
+        let m0 = 0b0110_0011_1000_0101u64;
+        let s0 = 0b0000_0010_0000_0101u64;
+
+        let m1 = 0b1110_1011_1110_1111u64;
+        let s1 = 0b1110_1001_0010_0011u64;
+
+        // Testing of random values.
+        assert_eq!(_pdep_u64(n, m0), s0);
+        assert_eq!(_pdep_u64(n, m1), s1);
+        assert_eq!(_pdep_u64(0x00012567, 0xff00fff0), 0x12005670);
+
+        // Testing of various identities.
+        assert_eq!(_pdep_u64(u64::MAX, u64::MAX), u64::MAX);
+        assert_eq!(_pdep_u64(0, u64::MAX), 0);
+        assert_eq!(_pdep_u64(u64::MAX, 0), 0);
+    }
+    test_pdep_u64();
+
+    unsafe fn test_bzhi_u64() {
+        let n = 0b1111_0010u64;
+        let s = 0b0001_0010u64;
+        assert_eq!(_bzhi_u64(n, 5), s);
+
+        // Ensure that indices larger than the bit count are covered.
+        // It is important to go above 255 in order to verify the bit selection
+        // of the instruction.
+        for i in 0..=512 {
+            // The instruction only takes the lowest eight bits to generate the index, hence `i & 0xff`.
+            // If the index is out of bounds, the original input won't be changed, thus the `min(64)`.
+            let expected = 1u64.checked_shl((i & 0xff).min(64)).unwrap_or(0).wrapping_sub(1);
+            let actual = _bzhi_u64(u64::MAX, i);
+            assert_eq!(expected, actual);
+        }
+    }
+    test_bzhi_u64();
+}
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 7cbfad3942b..b0e1adf27d1 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
@@ -4,12 +4,11 @@ warning: integer-to-pointer cast
 LL |         let wildcard = &root0 as *const Cell<i32> as usize as *const Cell<i32>;
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast
    |
-   = help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`,
-   = help: which means that Miri might miss pointer bugs in this program.
+   = help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, which means that Miri might miss pointer bugs in this program.
    = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation.
    = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead.
-   = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `with_exposed_provenance` semantics.
-   = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning.
+   = 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 $DIR/issue-miri-2389.rs:LL:CC
 
diff --git a/src/tools/miri/tests/pass/tail_call.rs b/src/tools/miri/tests/pass/tail_call.rs
new file mode 100644
index 00000000000..f6200706398
--- /dev/null
+++ b/src/tools/miri/tests/pass/tail_call.rs
@@ -0,0 +1,39 @@
+#![allow(incomplete_features)]
+#![feature(explicit_tail_calls)]
+
+fn main() {
+    assert_eq!(factorial(10), 3_628_800);
+    assert_eq!(mutually_recursive_identity(1000), 1000);
+}
+
+fn factorial(n: u32) -> u32 {
+    fn factorial_acc(n: u32, acc: u32) -> u32 {
+        match n {
+            0 => acc,
+            _ => become factorial_acc(n - 1, acc * n),
+        }
+    }
+
+    factorial_acc(n, 1)
+}
+
+// this is of course very silly, but we need to demonstrate mutual recursion somehow so...
+fn mutually_recursive_identity(x: u32) -> u32 {
+    fn switch(src: u32, tgt: u32) -> u32 {
+        match src {
+            0 => tgt,
+            _ if src % 7 == 0 => become advance_with_extra_steps(src, tgt),
+            _ => become advance(src, tgt),
+        }
+    }
+
+    fn advance(src: u32, tgt: u32) -> u32 {
+        become switch(src - 1, tgt + 1)
+    }
+
+    fn advance_with_extra_steps(src: u32, tgt: u32) -> u32 {
+        become advance(src, tgt)
+    }
+
+    switch(x, 0)
+}
diff --git a/src/tools/miri/tests/pass/tls/tls_macro_drop.rs b/src/tools/miri/tests/pass/tls/tls_macro_drop.rs
index bd06eec9cd5..0d8a1cef511 100644
--- a/src/tools/miri/tests/pass/tls/tls_macro_drop.rs
+++ b/src/tools/miri/tests/pass/tls/tls_macro_drop.rs
@@ -4,27 +4,28 @@
 use std::cell::RefCell;
 use std::thread;
 
-struct TestCell {
-    value: RefCell<u8>,
-}
+/// Check that destructors of the library thread locals are executed immediately
+/// after a thread terminates.
+fn check_destructors() {
+    struct TestCell {
+        value: RefCell<u8>,
+    }
 
-impl Drop for TestCell {
-    fn drop(&mut self) {
-        for _ in 0..10 {
-            thread::yield_now();
+    impl Drop for TestCell {
+        fn drop(&mut self) {
+            for _ in 0..10 {
+                thread::yield_now();
+            }
+            println!("Dropping: {} (should be before 'Continue main 1').", *self.value.borrow())
         }
-        println!("Dropping: {} (should be before 'Continue main 1').", *self.value.borrow())
     }
-}
 
-thread_local! {
-    static A: TestCell = TestCell { value: RefCell::new(0) };
-    static A_CONST: TestCell = const { TestCell { value: RefCell::new(10) } };
-}
+    // Test both regular and `const` thread-locals.
+    thread_local! {
+        static A: TestCell = TestCell { value: RefCell::new(0) };
+        static A_CONST: TestCell = const { TestCell { value: RefCell::new(10) } };
+    }
 
-/// Check that destructors of the library thread locals are executed immediately
-/// after a thread terminates.
-fn check_destructors() {
     // We use the same value for both of them, since destructor order differs between Miri on Linux
     // (which uses `register_dtor_fallback`, in the end using a single pthread_key to manage a
     // thread-local linked list of dtors to call), real Linux rustc (which uses
@@ -44,26 +45,29 @@ fn check_destructors() {
     println!("Continue main 1.")
 }
 
-struct JoinCell {
-    value: RefCell<Option<thread::JoinHandle<u8>>>,
-}
+/// Check that the destructor can be blocked joining another thread.
+fn check_blocking() {
+    struct JoinCell {
+        value: RefCell<Option<thread::JoinHandle<u8>>>,
+    }
 
-impl Drop for JoinCell {
-    fn drop(&mut self) {
-        for _ in 0..10 {
-            thread::yield_now();
+    impl Drop for JoinCell {
+        fn drop(&mut self) {
+            for _ in 0..10 {
+                thread::yield_now();
+            }
+            let join_handle = self.value.borrow_mut().take().unwrap();
+            println!(
+                "Joining: {} (should be before 'Continue main 2').",
+                join_handle.join().unwrap()
+            );
         }
-        let join_handle = self.value.borrow_mut().take().unwrap();
-        println!("Joining: {} (should be before 'Continue main 2').", join_handle.join().unwrap());
     }
-}
 
-thread_local! {
-    static B: JoinCell = JoinCell { value: RefCell::new(None) };
-}
+    thread_local! {
+        static B: JoinCell = JoinCell { value: RefCell::new(None) };
+    }
 
-/// Check that the destructor can be blocked joining another thread.
-fn check_blocking() {
     thread::spawn(|| {
         B.with(|f| {
             assert!(f.value.borrow().is_none());
@@ -74,10 +78,36 @@ fn check_blocking() {
     .join()
     .unwrap();
     println!("Continue main 2.");
-    // Preempt the main thread so that the destructor gets executed and can join
-    // the thread.
-    thread::yield_now();
-    thread::yield_now();
+}
+
+fn check_tls_init_in_dtor() {
+    struct Bar;
+
+    impl Drop for Bar {
+        fn drop(&mut self) {
+            println!("Bar dtor (should be before `Continue main 3`).");
+        }
+    }
+
+    struct Foo;
+
+    impl Drop for Foo {
+        fn drop(&mut self) {
+            println!("Foo dtor (should be before `Bar dtor`).");
+            // We initialize another thread-local inside the dtor, which is an interesting corner case.
+            thread_local!(static BAR: Bar = Bar);
+            BAR.with(|_| {});
+        }
+    }
+
+    thread_local!(static FOO: Foo = Foo);
+
+    thread::spawn(|| {
+        FOO.with(|_| {});
+    })
+    .join()
+    .unwrap();
+    println!("Continue main 3.");
 }
 
 // This test tests that TLS destructors have run before the thread joins. The
@@ -248,6 +278,8 @@ fn dtors_in_dtors_in_dtors() {
 fn main() {
     check_destructors();
     check_blocking();
+    check_tls_init_in_dtor();
+
     join_orders_after_tls_destructors();
     dtors_in_dtors_in_dtors();
 }
diff --git a/src/tools/miri/tests/pass/tls/tls_macro_drop.stack.stdout b/src/tools/miri/tests/pass/tls/tls_macro_drop.stack.stdout
index b7877820a0c..3e17acc8328 100644
--- a/src/tools/miri/tests/pass/tls/tls_macro_drop.stack.stdout
+++ b/src/tools/miri/tests/pass/tls/tls_macro_drop.stack.stdout
@@ -3,3 +3,6 @@ Dropping: 8 (should be before 'Continue main 1').
 Continue main 1.
 Joining: 7 (should be before 'Continue main 2').
 Continue main 2.
+Foo dtor (should be before `Bar dtor`).
+Bar dtor (should be before `Continue main 3`).
+Continue main 3.
diff --git a/src/tools/miri/tests/pass/tls/tls_macro_drop.tree.stdout b/src/tools/miri/tests/pass/tls/tls_macro_drop.tree.stdout
index b7877820a0c..3e17acc8328 100644
--- a/src/tools/miri/tests/pass/tls/tls_macro_drop.tree.stdout
+++ b/src/tools/miri/tests/pass/tls/tls_macro_drop.tree.stdout
@@ -3,3 +3,6 @@ Dropping: 8 (should be before 'Continue main 1').
 Continue main 1.
 Joining: 7 (should be before 'Continue main 2').
 Continue main 2.
+Foo dtor (should be before `Bar dtor`).
+Bar dtor (should be before `Continue main 3`).
+Continue main 3.
diff --git a/src/tools/miri/tests/pass/tls/tls_macro_drop_single_thread.rs b/src/tools/miri/tests/pass/tls/tls_macro_drop_single_thread.rs
index f36c460ae53..082a6f17838 100644
--- a/src/tools/miri/tests/pass/tls/tls_macro_drop_single_thread.rs
+++ b/src/tools/miri/tests/pass/tls/tls_macro_drop_single_thread.rs
@@ -1,31 +1,27 @@
-//! Check that destructors of the thread locals are executed on all OSes
-//! (even when we do not support concurrency, and cannot run the other test).
+//! Check that destructors of main thread thread locals are executed.
 
-use std::cell::RefCell;
+struct Bar;
 
-struct TestCell {
-    value: RefCell<u8>,
+impl Drop for Bar {
+    fn drop(&mut self) {
+        println!("Bar dtor");
+    }
 }
 
-impl Drop for TestCell {
+struct Foo;
+
+impl Drop for Foo {
     fn drop(&mut self) {
-        eprintln!("Dropping: {}", *self.value.borrow())
+        println!("Foo dtor");
+        // We initialize another thread-local inside the dtor, which is an interesting corner case.
+        // Also we use a `const` thread-local here, just to also have that code path covered.
+        thread_local!(static BAR: Bar = const { Bar });
+        BAR.with(|_| {});
     }
 }
 
-thread_local! {
-    static A: TestCell = TestCell { value: RefCell::new(0) };
-    static A_CONST: TestCell = const { TestCell { value: RefCell::new(10) } };
-}
+thread_local!(static FOO: Foo = Foo);
 
 fn main() {
-    A.with(|f| {
-        assert_eq!(*f.value.borrow(), 0);
-        *f.value.borrow_mut() = 5;
-    });
-    A_CONST.with(|f| {
-        assert_eq!(*f.value.borrow(), 10);
-        *f.value.borrow_mut() = 5; // Same value as above since the drop order is different on different platforms
-    });
-    eprintln!("Continue main.")
+    FOO.with(|_| {});
 }
diff --git a/src/tools/miri/tests/pass/tls/tls_macro_drop_single_thread.stderr b/src/tools/miri/tests/pass/tls/tls_macro_drop_single_thread.stderr
deleted file mode 100644
index 09ec1c3c2c5..00000000000
--- a/src/tools/miri/tests/pass/tls/tls_macro_drop_single_thread.stderr
+++ /dev/null
@@ -1,3 +0,0 @@
-Continue main.
-Dropping: 5
-Dropping: 5
diff --git a/src/tools/miri/tests/pass/tls/tls_macro_drop_single_thread.stdout b/src/tools/miri/tests/pass/tls/tls_macro_drop_single_thread.stdout
new file mode 100644
index 00000000000..6160f272649
--- /dev/null
+++ b/src/tools/miri/tests/pass/tls/tls_macro_drop_single_thread.stdout
@@ -0,0 +1,2 @@
+Foo dtor
+Bar dtor
diff --git a/src/tools/miri/tests/pass/tls/win_tls_callback.rs b/src/tools/miri/tests/pass/tls/win_tls_callback.rs
new file mode 100644
index 00000000000..99a8de29e91
--- /dev/null
+++ b/src/tools/miri/tests/pass/tls/win_tls_callback.rs
@@ -0,0 +1,16 @@
+//! Ensure that we call Windows TLS callbacks in the local crate.
+//@only-target-windows
+// Calling eprintln in the callback seems to (re-)initialize some thread-local storage
+// and then leak the memory allocated for that. Let's just ignore these leaks,
+// that's not what this test is about.
+//@compile-flags: -Zmiri-ignore-leaks
+
+#[link_section = ".CRT$XLB"]
+#[used] // Miri only considers explicitly `#[used]` statics for `lookup_link_section`
+pub static CALLBACK: unsafe extern "system" fn(*const (), u32, *const ()) = tls_callback;
+
+unsafe extern "system" fn tls_callback(_h: *const (), _dw_reason: u32, _pv: *const ()) {
+    eprintln!("in tls_callback");
+}
+
+fn main() {}
diff --git a/src/tools/miri/tests/pass/tls/win_tls_callback.stderr b/src/tools/miri/tests/pass/tls/win_tls_callback.stderr
new file mode 100644
index 00000000000..84795589544
--- /dev/null
+++ b/src/tools/miri/tests/pass/tls/win_tls_callback.stderr
@@ -0,0 +1 @@
+in tls_callback
diff --git a/src/tools/miri/tests/pass/vecdeque.rs b/src/tools/miri/tests/pass/vecdeque.rs
index 77c4ca5a04e..9153c428e18 100644
--- a/src/tools/miri/tests/pass/vecdeque.rs
+++ b/src/tools/miri/tests/pass/vecdeque.rs
@@ -31,8 +31,8 @@ fn main() {
     }
 
     // Regression test for Debug impl's
-    format!("{:?} {:?}", dst, dst.iter());
-    format!("{:?}", VecDeque::<u32>::new().iter());
+    let _ = format!("{:?} {:?}", dst, dst.iter());
+    let _ = format!("{:?}", VecDeque::<u32>::new().iter());
 
     for a in dst {
         assert_eq!(*a, 2);
diff --git a/src/tools/remote-test-client/src/main.rs b/src/tools/remote-test-client/src/main.rs
index dd2c09c430b..42de3caf547 100644
--- a/src/tools/remote-test-client/src/main.rs
+++ b/src/tools/remote-test-client/src/main.rs
@@ -71,7 +71,7 @@ fn spawn_emulator(target: &str, server: &Path, tmpdir: &Path, rootfs: Option<Pat
 
     // Wait for the emulator to come online
     loop {
-        let dur = Duration::from_millis(100);
+        let dur = Duration::from_millis(2000);
         if let Ok(mut client) = TcpStream::connect(&device_address) {
             t!(client.set_read_timeout(Some(dur)));
             t!(client.set_write_timeout(Some(dur)));
diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml
index 2f7f51442f1..ec3b8a96ef3 100644
--- a/src/tools/run-make-support/Cargo.toml
+++ b/src/tools/run-make-support/Cargo.toml
@@ -4,8 +4,10 @@ version = "0.2.0"
 edition = "2021"
 
 [dependencies]
+bstr = "1.6.0"
 object = "0.34.0"
 similar = "2.5.0"
 wasmparser = "0.118.2"
 regex = "1.8" # 1.8 to avoid memchr 2.6.0, as 2.5.0 is pinned in the workspace
 gimli = "0.28.1"
+ar = "0.9.0"
diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs
index f39bcfd60df..c506c3d6b61 100644
--- a/src/tools/run-make-support/src/command.rs
+++ b/src/tools/run-make-support/src/command.rs
@@ -36,8 +36,10 @@ impl Command {
         Self { cmd: StdCommand::new(program), stdin: None, drop_bomb: DropBomb::arm(program) }
     }
 
-    pub fn set_stdin(&mut self, stdin: Box<[u8]>) {
-        self.stdin = Some(stdin);
+    /// Specify a stdin input
+    pub fn stdin<I: AsRef<[u8]>>(&mut self, input: I) -> &mut Self {
+        self.stdin = Some(input.as_ref().to_vec().into_boxed_slice());
+        self
     }
 
     /// Specify an environment variable.
@@ -73,11 +75,12 @@ impl Command {
     /// Generic command arguments provider. Prefer specific helper methods if possible.
     /// Note that for some executables, arguments might be platform specific. For C/C++
     /// compilers, arguments might be platform *and* compiler specific.
-    pub fn args<S>(&mut self, args: &[S]) -> &mut Self
+    pub fn args<S, V>(&mut self, args: V) -> &mut Self
     where
         S: AsRef<ffi::OsStr>,
+        V: AsRef<[S]>,
     {
-        self.cmd.args(args);
+        self.cmd.args(args.as_ref());
         self
     }
 
@@ -183,14 +186,14 @@ impl CompletedProcess {
     /// Checks that `stdout` does not contain `unexpected`.
     #[track_caller]
     pub fn assert_stdout_not_contains<S: AsRef<str>>(&self, unexpected: S) -> &Self {
-        assert_not_contains(&self.stdout_utf8(), unexpected.as_ref());
+        assert_not_contains(&self.stdout_utf8(), unexpected);
         self
     }
 
     /// Checks that `stdout` contains `expected`.
     #[track_caller]
     pub fn assert_stdout_contains<S: AsRef<str>>(&self, expected: S) -> &Self {
-        assert_contains(&self.stdout_utf8(), expected.as_ref());
+        assert_contains(&self.stdout_utf8(), expected);
         self
     }
 
@@ -204,14 +207,14 @@ impl CompletedProcess {
     /// Checks that `stderr` contains `expected`.
     #[track_caller]
     pub fn assert_stderr_contains<S: AsRef<str>>(&self, expected: S) -> &Self {
-        assert_contains(&self.stderr_utf8(), expected.as_ref());
+        assert_contains(&self.stderr_utf8(), expected);
         self
     }
 
     /// Checks that `stderr` does not contain `unexpected`.
     #[track_caller]
     pub fn assert_stderr_not_contains<S: AsRef<str>>(&self, unexpected: S) -> &Self {
-        assert_not_contains(&self.stdout_utf8(), unexpected.as_ref());
+        assert_not_contains(&self.stdout_utf8(), unexpected);
         self
     }
 
diff --git a/src/tools/run-make-support/src/diff/mod.rs b/src/tools/run-make-support/src/diff/mod.rs
index 3e0bdc1c6f6..24fa88af82e 100644
--- a/src/tools/run-make-support/src/diff/mod.rs
+++ b/src/tools/run-make-support/src/diff/mod.rs
@@ -87,9 +87,7 @@ impl Diff {
         self
     }
 
-    #[track_caller]
-    pub fn run(&mut self) {
-        self.drop_bomb.defuse();
+    fn run_common(&self) -> (&str, &str, String, String) {
         let expected = self.expected.as_ref().expect("expected text not set");
         let mut actual = self.actual.as_ref().expect("actual text not set").to_string();
         let expected_name = self.expected_name.as_ref().unwrap();
@@ -104,6 +102,14 @@ impl Diff {
             .header(expected_name, actual_name)
             .to_string();
 
+        (expected_name, actual_name, output, actual)
+    }
+
+    #[track_caller]
+    pub fn run(&mut self) {
+        self.drop_bomb.defuse();
+        let (expected_name, actual_name, output, actual) = self.run_common();
+
         if !output.is_empty() {
             // If we can bless (meaning we have a file to write into and the `RUSTC_BLESS_TEST`
             // environment variable set), then we write into the file and return.
@@ -120,4 +126,26 @@ impl Diff {
             )
         }
     }
+
+    #[track_caller]
+    pub fn run_fail(&mut self) {
+        self.drop_bomb.defuse();
+        let (expected_name, actual_name, output, actual) = self.run_common();
+
+        if output.is_empty() {
+            // If we can bless (meaning we have a file to write into and the `RUSTC_BLESS_TEST`
+            // environment variable set), then we write into the file and return.
+            if let Some(ref expected_file) = self.expected_file {
+                if std::env::var("RUSTC_BLESS_TEST").is_ok() {
+                    println!("Blessing `{}`", expected_file.display());
+                    fs_wrapper::write(expected_file, actual);
+                    return;
+                }
+            }
+            panic!(
+                "test failed: `{}` is not different from `{}`\n\n{}",
+                expected_name, actual_name, output
+            )
+        }
+    }
 }
diff --git a/src/tools/run-make-support/src/fs_wrapper.rs b/src/tools/run-make-support/src/fs_wrapper.rs
index 8a2bfce8b4a..0f0d6f6618c 100644
--- a/src/tools/run-make-support/src/fs_wrapper.rs
+++ b/src/tools/run-make-support/src/fs_wrapper.rs
@@ -1,7 +1,7 @@
 use std::fs;
 use std::path::Path;
 
-/// A wrapper around [`std::fs::remove_file`] which includes the file path in the panic message..
+/// A wrapper around [`std::fs::remove_file`] which includes the file path in the panic message.
 #[track_caller]
 pub fn remove_file<P: AsRef<Path>>(path: P) {
     fs::remove_file(path.as_ref())
@@ -18,21 +18,21 @@ pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) {
     ));
 }
 
-/// A wrapper around [`std::fs::File::create`] which includes the file path in the panic message..
+/// A wrapper around [`std::fs::File::create`] which includes the file path in the panic message.
 #[track_caller]
 pub fn create_file<P: AsRef<Path>>(path: P) {
     fs::File::create(path.as_ref())
         .expect(&format!("the file in path \"{}\" could not be created", path.as_ref().display()));
 }
 
-/// A wrapper around [`std::fs::read`] which includes the file path in the panic message..
+/// A wrapper around [`std::fs::read`] which includes the file path in the panic message.
 #[track_caller]
 pub fn read<P: AsRef<Path>>(path: P) -> Vec<u8> {
     fs::read(path.as_ref())
         .expect(&format!("the file in path \"{}\" could not be read", path.as_ref().display()))
 }
 
-/// A wrapper around [`std::fs::read_to_string`] which includes the file path in the panic message..
+/// A wrapper around [`std::fs::read_to_string`] which includes the file path in the panic message.
 #[track_caller]
 pub fn read_to_string<P: AsRef<Path>>(path: P) -> String {
     fs::read_to_string(path.as_ref()).expect(&format!(
@@ -41,14 +41,14 @@ pub fn read_to_string<P: AsRef<Path>>(path: P) -> String {
     ))
 }
 
-/// A wrapper around [`std::fs::read_dir`] which includes the file path in the panic message..
+/// A wrapper around [`std::fs::read_dir`] which includes the file path in the panic message.
 #[track_caller]
 pub fn read_dir<P: AsRef<Path>>(path: P) -> fs::ReadDir {
     fs::read_dir(path.as_ref())
         .expect(&format!("the directory in path \"{}\" could not be read", path.as_ref().display()))
 }
 
-/// A wrapper around [`std::fs::write`] which includes the file path in the panic message..
+/// A wrapper around [`std::fs::write`] which includes the file path in the panic message.
 #[track_caller]
 pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) {
     fs::write(path.as_ref(), contents.as_ref()).expect(&format!(
@@ -57,7 +57,7 @@ pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) {
     ));
 }
 
-/// A wrapper around [`std::fs::remove_dir_all`] which includes the file path in the panic message..
+/// A wrapper around [`std::fs::remove_dir_all`] which includes the file path in the panic message.
 #[track_caller]
 pub fn remove_dir_all<P: AsRef<Path>>(path: P) {
     fs::remove_dir_all(path.as_ref()).expect(&format!(
@@ -66,7 +66,7 @@ pub fn remove_dir_all<P: AsRef<Path>>(path: P) {
     ));
 }
 
-/// A wrapper around [`std::fs::create_dir`] which includes the file path in the panic message..
+/// A wrapper around [`std::fs::create_dir`] which includes the file path in the panic message.
 #[track_caller]
 pub fn create_dir<P: AsRef<Path>>(path: P) {
     fs::create_dir(path.as_ref()).expect(&format!(
@@ -75,7 +75,7 @@ pub fn create_dir<P: AsRef<Path>>(path: P) {
     ));
 }
 
-/// A wrapper around [`std::fs::create_dir_all`] which includes the file path in the panic message..
+/// A wrapper around [`std::fs::create_dir_all`] which includes the file path in the panic message.
 #[track_caller]
 pub fn create_dir_all<P: AsRef<Path>>(path: P) {
     fs::create_dir_all(path.as_ref()).expect(&format!(
@@ -84,7 +84,7 @@ pub fn create_dir_all<P: AsRef<Path>>(path: P) {
     ));
 }
 
-/// A wrapper around [`std::fs::metadata`] which includes the file path in the panic message..
+/// A wrapper around [`std::fs::metadata`] which includes the file path in the panic message.
 #[track_caller]
 pub fn metadata<P: AsRef<Path>>(path: P) -> fs::Metadata {
     fs::metadata(path.as_ref()).expect(&format!(
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index f4c101cf81c..5655318267a 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -21,6 +21,7 @@ use std::io;
 use std::panic;
 use std::path::{Path, PathBuf};
 
+pub use bstr;
 pub use gimli;
 pub use object;
 pub use regex;
@@ -34,7 +35,7 @@ pub use llvm::{
     LlvmProfdata, LlvmReadobj,
 };
 pub use run::{cmd, run, run_fail, run_with_args};
-pub use rustc::{aux_build, rustc, Rustc};
+pub use rustc::{aux_build, bare_rustc, rustc, Rustc};
 pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc};
 
 #[track_caller]
@@ -61,6 +62,19 @@ pub fn target() -> String {
     env_var("TARGET")
 }
 
+/// `AR`
+#[track_caller]
+pub fn ar(inputs: &[impl AsRef<Path>], output_path: impl AsRef<Path>) {
+    let output = fs::File::create(&output_path).expect(&format!(
+        "the file in path \"{}\" could not be created",
+        output_path.as_ref().display()
+    ));
+    let mut builder = ar::Builder::new(output);
+    for input in inputs {
+        builder.append_path(input).unwrap();
+    }
+}
+
 /// Check if target is windows-like.
 #[must_use]
 pub fn is_windows() -> bool {
@@ -247,6 +261,62 @@ pub fn test_while_readonly<P: AsRef<Path>, F: FnOnce() + std::panic::UnwindSafe>
     success.unwrap();
 }
 
+/// Browse the directory `path` non-recursively and return all files which respect the parameters
+/// outlined by `closure`.
+#[track_caller]
+pub fn shallow_find_files<P: AsRef<Path>, F: Fn(&PathBuf) -> bool>(
+    path: P,
+    filter: F,
+) -> Vec<PathBuf> {
+    let mut matching_files = Vec::new();
+    for entry in fs_wrapper::read_dir(path) {
+        let entry = entry.expect("failed to read directory entry.");
+        let path = entry.path();
+
+        if path.is_file() && filter(&path) {
+            matching_files.push(path);
+        }
+    }
+    matching_files
+}
+
+/// Returns true if the filename at `path` starts with `prefix`.
+pub fn has_prefix<P: AsRef<Path>>(path: P, prefix: &str) -> bool {
+    path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().starts_with(prefix))
+}
+
+/// Returns true if the filename at `path` has the extension `extension`.
+pub fn has_extension<P: AsRef<Path>>(path: P, extension: &str) -> bool {
+    path.as_ref().extension().is_some_and(|ext| ext == extension)
+}
+
+/// Returns true if the filename at `path` does not contain `expected`.
+pub fn not_contains<P: AsRef<Path>>(path: P, expected: &str) -> bool {
+    !path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().contains(expected))
+}
+
+/// Returns true if the filename at `path` is not in `expected`.
+pub fn filename_not_in_denylist<P: AsRef<Path>, V: AsRef<[String]>>(path: P, expected: V) -> bool {
+    let expected = expected.as_ref();
+    path.as_ref()
+        .file_name()
+        .is_some_and(|name| !expected.contains(&name.to_str().unwrap().to_owned()))
+}
+
+/// Gathers all files in the current working directory that have the extension `ext`, and counts
+/// the number of lines within that contain a match with the regex pattern `re`.
+pub fn count_regex_matches_in_files_with_extension(re: &regex::Regex, ext: &str) -> usize {
+    let fetched_files = shallow_find_files(cwd(), |path| has_extension(path, ext));
+
+    let mut count = 0;
+    for file in fetched_files {
+        let content = fs_wrapper::read_to_string(file);
+        count += content.lines().filter(|line| re.is_match(&line)).count();
+    }
+
+    count
+}
+
 /// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is
 /// available on the platform!
 #[track_caller]
@@ -307,8 +377,9 @@ pub fn set_host_rpath(cmd: &mut Command) {
 /// Read the contents of a file that cannot simply be read by
 /// read_to_string, due to invalid utf8 data, then assert that it contains `expected`.
 #[track_caller]
-pub fn invalid_utf8_contains<P: AsRef<Path>>(path: P, expected: &str) {
+pub fn invalid_utf8_contains<P: AsRef<Path>, S: AsRef<str>>(path: P, expected: S) {
     let buffer = fs_wrapper::read(path.as_ref());
+    let expected = expected.as_ref();
     if !String::from_utf8_lossy(&buffer).contains(expected) {
         eprintln!("=== FILE CONTENTS (LOSSY) ===");
         eprintln!("{}", String::from_utf8_lossy(&buffer));
@@ -321,8 +392,9 @@ pub fn invalid_utf8_contains<P: AsRef<Path>>(path: P, expected: &str) {
 /// Read the contents of a file that cannot simply be read by
 /// read_to_string, due to invalid utf8 data, then assert that it does not contain `expected`.
 #[track_caller]
-pub fn invalid_utf8_not_contains<P: AsRef<Path>>(path: P, expected: &str) {
+pub fn invalid_utf8_not_contains<P: AsRef<Path>, S: AsRef<str>>(path: P, expected: S) {
     let buffer = fs_wrapper::read(path.as_ref());
+    let expected = expected.as_ref();
     if String::from_utf8_lossy(&buffer).contains(expected) {
         eprintln!("=== FILE CONTENTS (LOSSY) ===");
         eprintln!("{}", String::from_utf8_lossy(&buffer));
@@ -387,7 +459,7 @@ pub fn recursive_diff(dir1: impl AsRef<Path>, dir2: impl AsRef<Path>) {
     });
 }
 
-pub fn read_dir<F: Fn(&Path)>(dir: impl AsRef<Path>, callback: F) {
+pub fn read_dir<F: FnMut(&Path)>(dir: impl AsRef<Path>, mut callback: F) {
     for entry in fs_wrapper::read_dir(dir) {
         callback(&entry.unwrap().path());
     }
@@ -395,7 +467,9 @@ pub fn read_dir<F: Fn(&Path)>(dir: impl AsRef<Path>, callback: F) {
 
 /// Check that `actual` is equal to `expected`. Panic otherwise.
 #[track_caller]
-pub fn assert_equals(actual: &str, expected: &str) {
+pub fn assert_equals<S1: AsRef<str>, S2: AsRef<str>>(actual: S1, expected: S2) {
+    let actual = actual.as_ref();
+    let expected = expected.as_ref();
     if actual != expected {
         eprintln!("=== ACTUAL TEXT ===");
         eprintln!("{}", actual);
@@ -407,7 +481,9 @@ pub fn assert_equals(actual: &str, expected: &str) {
 
 /// Check that `haystack` contains `needle`. Panic otherwise.
 #[track_caller]
-pub fn assert_contains(haystack: &str, needle: &str) {
+pub fn assert_contains<S1: AsRef<str>, S2: AsRef<str>>(haystack: S1, needle: S2) {
+    let haystack = haystack.as_ref();
+    let needle = needle.as_ref();
     if !haystack.contains(needle) {
         eprintln!("=== HAYSTACK ===");
         eprintln!("{}", haystack);
@@ -419,7 +495,9 @@ pub fn assert_contains(haystack: &str, needle: &str) {
 
 /// Check that `haystack` does not contain `needle`. Panic otherwise.
 #[track_caller]
-pub fn assert_not_contains(haystack: &str, needle: &str) {
+pub fn assert_not_contains<S1: AsRef<str>, S2: AsRef<str>>(haystack: S1, needle: S2) {
+    let haystack = haystack.as_ref();
+    let needle = needle.as_ref();
     if haystack.contains(needle) {
         eprintln!("=== HAYSTACK ===");
         eprintln!("{}", haystack);
@@ -511,11 +589,12 @@ macro_rules! impl_common_helpers {
             /// Generic command arguments provider. Prefer specific helper methods if possible.
             /// Note that for some executables, arguments might be platform specific. For C/C++
             /// compilers, arguments might be platform *and* compiler specific.
-            pub fn args<S>(&mut self, args: &[S]) -> &mut Self
+            pub fn args<V, S>(&mut self, args: V) -> &mut Self
             where
+                V: AsRef<[S]>,
                 S: AsRef<::std::ffi::OsStr>,
             {
-                self.cmd.args(args);
+                self.cmd.args(args.as_ref());
                 self
             }
 
diff --git a/src/tools/run-make-support/src/llvm.rs b/src/tools/run-make-support/src/llvm.rs
index 99bce08fc23..4c9e9a53230 100644
--- a/src/tools/run-make-support/src/llvm.rs
+++ b/src/tools/run-make-support/src/llvm.rs
@@ -102,6 +102,24 @@ impl LlvmReadobj {
         self
     }
 
+    /// Pass `--program-headers` to display program headers.
+    pub fn program_headers(&mut self) -> &mut Self {
+        self.cmd.arg("--program-headers");
+        self
+    }
+
+    /// Pass `--symbols` to display the symbol.
+    pub fn symbols(&mut self) -> &mut Self {
+        self.cmd.arg("--symbols");
+        self
+    }
+
+    /// Pass `--dynamic-table` to display the dynamic symbol table.
+    pub fn dynamic_table(&mut self) -> &mut Self {
+        self.cmd.arg("--dynamic-table");
+        self
+    }
+
     /// Specify the section to display.
     pub fn section(&mut self, section: &str) -> &mut Self {
         self.cmd.arg("--string-dump");
@@ -153,7 +171,7 @@ impl LlvmFilecheck {
 
     /// Pipe a read file into standard input containing patterns that will be matched against the .patterns(path) call.
     pub fn stdin<I: AsRef<[u8]>>(&mut self, input: I) -> &mut Self {
-        self.cmd.set_stdin(input.as_ref().to_vec().into_boxed_slice());
+        self.cmd.stdin(input);
         self
     }
 
@@ -162,6 +180,13 @@ impl LlvmFilecheck {
         self.cmd.arg(path.as_ref());
         self
     }
+
+    /// `--input-file` option.
+    pub fn input_file<P: AsRef<Path>>(&mut self, input_file: P) -> &mut Self {
+        self.cmd.arg("--input-file");
+        self.cmd.arg(input_file.as_ref());
+        self
+    }
 }
 
 impl LlvmObjdump {
diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs
index 331e1a5ab8b..a2a7c8064dc 100644
--- a/src/tools/run-make-support/src/rustc.rs
+++ b/src/tools/run-make-support/src/rustc.rs
@@ -10,6 +10,12 @@ pub fn rustc() -> Rustc {
     Rustc::new()
 }
 
+/// Construct a plain `rustc` invocation with no flags set.
+#[track_caller]
+pub fn bare_rustc() -> Rustc {
+    Rustc::bare()
+}
+
 /// Construct a new `rustc` aux-build invocation.
 #[track_caller]
 pub fn aux_build() -> Rustc {
@@ -30,7 +36,6 @@ fn setup_common() -> Command {
     let rustc = env_var("RUSTC");
     let mut cmd = Command::new(rustc);
     set_host_rpath(&mut cmd);
-    cmd.arg("-L").arg(cwd());
     cmd
 }
 
@@ -40,6 +45,14 @@ impl Rustc {
     /// Construct a new `rustc` invocation.
     #[track_caller]
     pub fn new() -> Self {
+        let mut cmd = setup_common();
+        cmd.arg("-L").arg(cwd());
+        Self { cmd }
+    }
+
+    /// Construct a bare `rustc` invocation with no flags set.
+    #[track_caller]
+    pub fn bare() -> Self {
         let cmd = setup_common();
         Self { cmd }
     }
@@ -73,6 +86,12 @@ impl Rustc {
         self
     }
 
+    /// Incorporate a hashed string to mangled symbols.
+    pub fn metadata(&mut self, meta: &str) -> &mut Self {
+        self.cmd.arg(format!("-Cmetadata={meta}"));
+        self
+    }
+
     /// Add a suffix in each output filename.
     pub fn extra_filename(&mut self, suffix: &str) -> &mut Self {
         self.cmd.arg(format!("-Cextra-filename={suffix}"));
@@ -80,7 +99,8 @@ impl Rustc {
     }
 
     /// Specify type(s) of output files to generate.
-    pub fn emit(&mut self, kinds: &str) -> &mut Self {
+    pub fn emit<S: AsRef<str>>(&mut self, kinds: S) -> &mut Self {
+        let kinds = kinds.as_ref();
         self.cmd.arg(format!("--emit={kinds}"));
         self
     }
@@ -100,6 +120,21 @@ impl Rustc {
         self
     }
 
+    /// Remap source path prefixes in all output.
+    pub fn remap_path_prefix<P: AsRef<Path>, P2: AsRef<Path>>(
+        &mut self,
+        from: P,
+        to: P2,
+    ) -> &mut Self {
+        let from = from.as_ref().to_string_lossy();
+        let to = to.as_ref().to_string_lossy();
+
+        self.cmd.arg("--remap-path-prefix");
+        self.cmd.arg(format!("{from}={to}"));
+
+        self
+    }
+
     /// Specify path to the input file.
     pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
         self.cmd.arg(path.as_ref());
@@ -184,7 +219,8 @@ impl Rustc {
     }
 
     /// Specify the target triple, or a path to a custom target json spec file.
-    pub fn target(&mut self, target: &str) -> &mut Self {
+    pub fn target<S: AsRef<str>>(&mut self, target: S) -> &mut Self {
+        let target = target.as_ref();
         self.cmd.arg(format!("--target={target}"));
         self
     }
@@ -230,9 +266,15 @@ impl Rustc {
         self
     }
 
+    /// Add multiple extra arguments to the linker invocation, via `-Clink-args`.
+    pub fn link_args(&mut self, link_args: &str) -> &mut Self {
+        self.cmd.arg(format!("-Clink-args={link_args}"));
+        self
+    }
+
     /// Specify a stdin input
     pub fn stdin<I: AsRef<[u8]>>(&mut self, input: I) -> &mut Self {
-        self.cmd.set_stdin(input.as_ref().to_vec().into_boxed_slice());
+        self.cmd.stdin(input);
         self
     }
 
@@ -248,4 +290,10 @@ impl Rustc {
         self.cmd.arg(format!("-Clinker={linker}"));
         self
     }
+
+    /// Specify the linker flavor
+    pub fn linker_flavor(&mut self, linker_flavor: &str) -> &mut Self {
+        self.cmd.arg(format!("-Clinker-flavor={linker_flavor}"));
+        self
+    }
 }
diff --git a/src/tools/run-make-support/src/rustdoc.rs b/src/tools/run-make-support/src/rustdoc.rs
index 93078561254..2be962ad888 100644
--- a/src/tools/run-make-support/src/rustdoc.rs
+++ b/src/tools/run-make-support/src/rustdoc.rs
@@ -92,7 +92,7 @@ impl Rustdoc {
 
     /// Specify a stdin input
     pub fn stdin<I: AsRef<[u8]>>(&mut self, input: I) -> &mut Self {
-        self.cmd.set_stdin(input.as_ref().to_vec().into_boxed_slice());
+        self.cmd.stdin(input);
         self
     }
 
@@ -104,7 +104,8 @@ impl Rustdoc {
     }
 
     /// Specify the target triple, or a path to a custom target json spec file.
-    pub fn target(&mut self, target: &str) -> &mut Self {
+    pub fn target<S: AsRef<str>>(&mut self, target: S) -> &mut Self {
+        let target = target.as_ref();
         self.cmd.arg(format!("--target={target}"));
         self
     }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs
index 35fd85bf451..7ead7e93901 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs
@@ -142,9 +142,9 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
         allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
         DuplicatesOk, @only_local: true,
     ),
-    gated!(
-        expect, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk,
-        lint_reasons, experimental!(expect)
+    ungated!(
+        expect, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
+        DuplicatesOk, @only_local: true,
     ),
     ungated!(
         forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
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 2e0235768cc..0504f3caf5f 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
@@ -49,7 +49,6 @@ pub const DEFAULT_LINTS: &[Lint] = &[
         label: "bindings_with_variant_name",
         description: r##"detects pattern bindings with the same name as one of the matched variants"##,
     },
-    Lint { label: "box_pointers", description: r##"use of owned (Box type) heap memory"## },
     Lint {
         label: "boxed_slice_into_iter",
         description: r##"detects calling `into_iter` on boxed slices in Rust 2015, 2018, and 2021"##,
diff --git a/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/database_storage.rs b/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/database_storage.rs
index 14238e2fed5..f16d814b9f0 100644
--- a/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/database_storage.rs
+++ b/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/database_storage.rs
@@ -241,11 +241,3 @@ impl Parse for QueryGroup {
         Ok(QueryGroup { group_path })
     }
 }
-
-struct Nothing;
-
-impl Parse for Nothing {
-    fn parse(_input: ParseStream<'_>) -> syn::Result<Self> {
-        Ok(Nothing)
-    }
-}
diff --git a/src/tools/rust-analyzer/crates/stdx/src/anymap.rs b/src/tools/rust-analyzer/crates/stdx/src/anymap.rs
index d189b56a468..4eafcfb060f 100644
--- a/src/tools/rust-analyzer/crates/stdx/src/anymap.rs
+++ b/src/tools/rust-analyzer/crates/stdx/src/anymap.rs
@@ -68,8 +68,6 @@ pub type RawMap<A> = hash_map::HashMap<TypeId, Box<A>, BuildHasherDefault<TypeId
 /// The type parameter `A` allows you to use a different value type; normally you will want
 /// it to be `core::any::Any` (also known as `std::any::Any`), but there are other choices:
 ///
-/// - If you want the entire map to be cloneable, use `CloneAny` instead of `Any`; with
-///   that, you can only add types that implement `Clone` to the map.
 /// - You can add on `+ Send` or `+ Send + Sync` (e.g. `Map<dyn Any + Send>`) to add those
 ///   auto traits.
 ///
@@ -79,9 +77,6 @@ pub type RawMap<A> = hash_map::HashMap<TypeId, Box<A>, BuildHasherDefault<TypeId
 ///   also spelled [`AnyMap`] for convenience.
 /// - <code>[Map]&lt;dyn [core::any::Any] + Send&gt;</code>
 /// - <code>[Map]&lt;dyn [core::any::Any] + Send + Sync&gt;</code>
-/// - <code>[Map]&lt;dyn [CloneAny]&gt;</code>
-/// - <code>[Map]&lt;dyn [CloneAny] + Send&gt;</code>
-/// - <code>[Map]&lt;dyn [CloneAny] + Send + Sync&gt;</code>
 ///
 /// ## Example
 ///
@@ -205,12 +200,6 @@ mod tests {
         assert_debug::<Map<dyn Any>>();
         assert_debug::<Map<dyn Any + Send>>();
         assert_debug::<Map<dyn Any + Send + Sync>>();
-        assert_send::<Map<dyn CloneAny + Send>>();
-        assert_send::<Map<dyn CloneAny + Send + Sync>>();
-        assert_sync::<Map<dyn CloneAny + Send + Sync>>();
-        assert_debug::<Map<dyn CloneAny>>();
-        assert_debug::<Map<dyn CloneAny + Send>>();
-        assert_debug::<Map<dyn CloneAny + Send + Sync>>();
     }
 
     #[test]
@@ -232,53 +221,6 @@ mod tests {
     }
 }
 
-// impl some traits for dyn Any
-use core::fmt;
-
-#[doc(hidden)]
-pub trait CloneToAny {
-    /// Clone `self` into a new `Box<dyn CloneAny>` object.
-    fn clone_to_any(&self) -> Box<dyn CloneAny>;
-}
-
-impl<T: Any + Clone> CloneToAny for T {
-    #[inline]
-    fn clone_to_any(&self) -> Box<dyn CloneAny> {
-        Box::new(self.clone())
-    }
-}
-
-macro_rules! impl_clone {
-    ($t:ty) => {
-        impl Clone for Box<$t> {
-            #[inline]
-            fn clone(&self) -> Box<$t> {
-                // SAFETY: this dance is to reapply any Send/Sync marker. I’m not happy about this
-                // approach, given that I used to do it in safe code, but then came a dodgy
-                // future-compatibility warning where_clauses_object_safety, which is spurious for
-                // auto traits but still super annoying (future-compatibility lints seem to mean
-                // your bin crate needs a corresponding allow!). Although I explained my plight¹
-                // and it was all explained and agreed upon, no action has been taken. So I finally
-                // caved and worked around it by doing it this way, which matches what’s done for
-                // core::any², so it’s probably not *too* bad.
-                //
-                // ¹ https://github.com/rust-lang/rust/issues/51443#issuecomment-421988013
-                // ² https://github.com/rust-lang/rust/blob/e7825f2b690c9a0d21b6f6d84c404bb53b151b38/library/alloc/src/boxed.rs#L1613-L1616
-                let clone: Box<dyn CloneAny> = (**self).clone_to_any();
-                let raw: *mut dyn CloneAny = Box::into_raw(clone);
-                unsafe { Box::from_raw(raw as *mut $t) }
-            }
-        }
-
-        impl fmt::Debug for $t {
-            #[inline]
-            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-                f.pad(stringify!($t))
-            }
-        }
-    };
-}
-
 /// Methods for downcasting from an `Any`-like trait object.
 ///
 /// This should only be implemented on trait objects for subtraits of `Any`, though you can
@@ -350,16 +292,3 @@ macro_rules! implement {
 implement!(Any);
 implement!(Any + Send);
 implement!(Any + Send + Sync);
-
-/// [`Any`], but with cloning.
-///
-/// Every type with no non-`'static` references that implements `Clone` implements `CloneAny`.
-/// See [`core::any`] for more details on `Any` in general.
-pub trait CloneAny: Any + CloneToAny {}
-impl<T: Any + Clone> CloneAny for T {}
-implement!(CloneAny);
-implement!(CloneAny + Send);
-implement!(CloneAny + Send + Sync);
-impl_clone!(dyn CloneAny);
-impl_clone!(dyn CloneAny + Send);
-impl_clone!(dyn CloneAny + Send + Sync);
diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version
index c605feb6eea..424c93a7521 100644
--- a/src/tools/rust-analyzer/rust-version
+++ b/src/tools/rust-analyzer/rust-version
@@ -1 +1 @@
-3d5d7a24f76006b391d8a53d903ae64c1b4a52d2
+bcf1f6db4594ae6132378b179a30cdb3599a863d
diff --git a/src/tools/rust-installer/src/combiner.rs b/src/tools/rust-installer/src/combiner.rs
index 565d19d863f..c211b34850a 100644
--- a/src/tools/rust-installer/src/combiner.rs
+++ b/src/tools/rust-installer/src/combiner.rs
@@ -55,6 +55,12 @@ actor! {
         /// The formats used to compress the tarball
         #[arg(value_name = "FORMAT", default_value_t)]
         compression_formats: CompressionFormats,
+
+        /// Modification time that will be set for all files added to the archive.
+        /// The default is the date of the first Rust commit from 2006.
+        /// This serves for better reproducibility of the archives.
+        #[arg(value_name = "FILE_MTIME", default_value_t = 1153704088)]
+        override_file_mtime: u64,
     }
 }
 
@@ -145,7 +151,8 @@ impl Combiner {
             .input(self.package_name)
             .output(path_to_str(&output)?.into())
             .compression_profile(self.compression_profile)
-            .compression_formats(self.compression_formats);
+            .compression_formats(self.compression_formats)
+            .override_file_mtime(self.override_file_mtime);
         tarballer.run()?;
 
         Ok(())
diff --git a/src/tools/rust-installer/src/generator.rs b/src/tools/rust-installer/src/generator.rs
index b101e67d8df..035a394deeb 100644
--- a/src/tools/rust-installer/src/generator.rs
+++ b/src/tools/rust-installer/src/generator.rs
@@ -61,6 +61,12 @@ actor! {
         /// The formats used to compress the tarball
         #[arg(value_name = "FORMAT", default_value_t)]
         compression_formats: CompressionFormats,
+
+        /// Modification time that will be set for all files added to the archive.
+        /// The default is the date of the first Rust commit from 2006.
+        /// This serves for better reproducibility of the archives.
+        #[arg(value_name = "FILE_MTIME", default_value_t = 1153704088)]
+        override_file_mtime: u64,
     }
 }
 
@@ -114,7 +120,8 @@ impl Generator {
             .input(self.package_name)
             .output(path_to_str(&output)?.into())
             .compression_profile(self.compression_profile)
-            .compression_formats(self.compression_formats);
+            .compression_formats(self.compression_formats)
+            .override_file_mtime(self.override_file_mtime);
         tarballer.run()?;
 
         Ok(())
diff --git a/src/tools/rust-installer/src/tarballer.rs b/src/tools/rust-installer/src/tarballer.rs
index 2f093e7ad17..b5e87a66ffc 100644
--- a/src/tools/rust-installer/src/tarballer.rs
+++ b/src/tools/rust-installer/src/tarballer.rs
@@ -32,6 +32,12 @@ actor! {
         /// The formats used to compress the tarball.
         #[arg(value_name = "FORMAT", default_value_t)]
         compression_formats: CompressionFormats,
+
+        /// Modification time that will be set for all files added to the archive.
+        /// The default is the date of the first Rust commit from 2006.
+        /// This serves for better reproducibility of the archives.
+        #[arg(value_name = "FILE_MTIME", default_value_t = 1153704088)]
+        override_file_mtime: u64,
     }
 }
 
@@ -65,6 +71,8 @@ impl Tarballer {
         let buf = BufWriter::with_capacity(1024 * 1024, encoder);
         let mut builder = Builder::new(buf);
         // Make uid, gid and mtime deterministic to improve reproducibility
+        // The modification time of directories will be set to the date of the first Rust commit.
+        // The modification time of files will be set to `override_file_mtime` (see `append_path`).
         builder.mode(HeaderMode::Deterministic);
 
         let pool = rayon::ThreadPoolBuilder::new().num_threads(2).build().unwrap();
@@ -77,7 +85,7 @@ impl Tarballer {
             }
             for path in files {
                 let src = Path::new(&self.work_dir).join(&path);
-                append_path(&mut builder, &src, &path)
+                append_path(&mut builder, &src, &path, self.override_file_mtime)
                     .with_context(|| format!("failed to tar file '{}'", src.display()))?;
             }
             builder
@@ -93,10 +101,16 @@ impl Tarballer {
     }
 }
 
-fn append_path<W: Write>(builder: &mut Builder<W>, src: &Path, path: &String) -> Result<()> {
+fn append_path<W: Write>(
+    builder: &mut Builder<W>,
+    src: &Path,
+    path: &String,
+    override_file_mtime: u64,
+) -> Result<()> {
     let stat = symlink_metadata(src)?;
     let mut header = Header::new_gnu();
     header.set_metadata_in_mode(&stat, HeaderMode::Deterministic);
+    header.set_mtime(override_file_mtime);
 
     if stat.file_type().is_symlink() {
         let link = read_link(src)?;
diff --git a/src/tools/rustc-perf-wrapper/Cargo.toml b/src/tools/rustc-perf-wrapper/Cargo.toml
new file mode 100644
index 00000000000..416bfef41d7
--- /dev/null
+++ b/src/tools/rustc-perf-wrapper/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+name = "rustc-perf-wrapper"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+clap = { version = "4.5.7", features = ["derive", "env"] }
diff --git a/src/tools/rustc-perf-wrapper/README.md b/src/tools/rustc-perf-wrapper/README.md
new file mode 100644
index 00000000000..d7655459a2f
--- /dev/null
+++ b/src/tools/rustc-perf-wrapper/README.md
@@ -0,0 +1,3 @@
+# rustc-perf wrapper
+Utility tool for invoking [`rustc-perf`](https://github.com/rust-lang/rustc-perf) for benchmarking/profiling
+a stage1/2 compiler built by bootstrap using `x perf -- <command>`.
diff --git a/src/tools/rustc-perf-wrapper/src/config.rs b/src/tools/rustc-perf-wrapper/src/config.rs
new file mode 100644
index 00000000000..a88abfe4723
--- /dev/null
+++ b/src/tools/rustc-perf-wrapper/src/config.rs
@@ -0,0 +1,45 @@
+use std::fmt::{Display, Formatter};
+
+#[derive(Clone, Copy, Debug, clap::ValueEnum)]
+#[value(rename_all = "PascalCase")]
+pub enum Profile {
+    Check,
+    Debug,
+    Doc,
+    Opt,
+    Clippy,
+}
+
+impl Display for Profile {
+    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+        let name = match self {
+            Profile::Check => "Check",
+            Profile::Debug => "Debug",
+            Profile::Doc => "Doc",
+            Profile::Opt => "Opt",
+            Profile::Clippy => "Clippy",
+        };
+        f.write_str(name)
+    }
+}
+
+#[derive(Clone, Copy, Debug, clap::ValueEnum)]
+#[value(rename_all = "PascalCase")]
+pub enum Scenario {
+    Full,
+    IncrFull,
+    IncrUnchanged,
+    IncrPatched,
+}
+
+impl Display for Scenario {
+    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+        let name = match self {
+            Scenario::Full => "Full",
+            Scenario::IncrFull => "IncrFull",
+            Scenario::IncrUnchanged => "IncrUnchanged",
+            Scenario::IncrPatched => "IncrPatched",
+        };
+        f.write_str(name)
+    }
+}
diff --git a/src/tools/rustc-perf-wrapper/src/main.rs b/src/tools/rustc-perf-wrapper/src/main.rs
new file mode 100644
index 00000000000..1c0d1745f3d
--- /dev/null
+++ b/src/tools/rustc-perf-wrapper/src/main.rs
@@ -0,0 +1,130 @@
+use crate::config::{Profile, Scenario};
+use clap::Parser;
+use std::path::PathBuf;
+use std::process::Command;
+
+mod config;
+
+/// Performs profiling or benchmarking with [`rustc-perf`](https://github.com/rust-lang/rustc-perf)
+/// using a locally built compiler.
+#[derive(Debug, clap::Parser)]
+// Hide arguments from BuildContext in the default usage string.
+// Clap does not seem to have a way of disabling the usage of these arguments.
+#[clap(override_usage = "rustc-perf-wrapper [OPTIONS] <COMMAND>")]
+pub struct Args {
+    #[clap(subcommand)]
+    cmd: PerfCommand,
+
+    #[clap(flatten)]
+    opts: SharedOpts,
+
+    #[clap(flatten)]
+    ctx: BuildContext,
+}
+
+#[derive(Debug, clap::Parser)]
+enum PerfCommand {
+    /// Run `profile_local eprintln`.
+    /// This executes the compiler on the given benchmarks and stores its stderr output.
+    Eprintln,
+    /// Run `profile_local samply`
+    /// This executes the compiler on the given benchmarks and profiles it with `samply`.
+    /// You need to install `samply`, e.g. using `cargo install samply`.
+    Samply,
+    /// Run `profile_local cachegrind`.
+    /// This executes the compiler on the given benchmarks under `Cachegrind`.
+    Cachegrind,
+}
+
+impl PerfCommand {
+    fn is_profiling(&self) -> bool {
+        match self {
+            PerfCommand::Eprintln | PerfCommand::Samply | PerfCommand::Cachegrind => true,
+        }
+    }
+}
+
+#[derive(Debug, clap::Parser)]
+struct SharedOpts {
+    /// Select the benchmarks that you want to run (separated by commas).
+    /// If unspecified, all benchmarks will be executed.
+    #[clap(long, global = true, value_delimiter = ',')]
+    include: Vec<String>,
+    /// Select the scenarios that should be benchmarked.
+    #[clap(
+        long,
+        global = true,
+        value_delimiter = ',',
+        default_value = "Full,IncrFull,IncrUnchanged,IncrPatched"
+    )]
+    scenarios: Vec<Scenario>,
+    /// Select the profiles that should be benchmarked.
+    #[clap(long, global = true, value_delimiter = ',', default_value = "Check,Debug,Opt")]
+    profiles: Vec<Profile>,
+}
+
+/// These arguments are mostly designed to be passed from bootstrap, not by users
+/// directly.
+#[derive(Debug, clap::Parser)]
+struct BuildContext {
+    /// Compiler binary that will be benchmarked/profiled.
+    #[clap(long, hide = true, env = "RUSTC_REAL")]
+    compiler: PathBuf,
+    /// rustc-perf collector binary that will be used for running benchmarks/profilers.
+    #[clap(long, hide = true, env = "PERF_COLLECTOR")]
+    collector: PathBuf,
+    /// Directory where to store results.
+    #[clap(long, hide = true, env = "PERF_RESULT_DIR")]
+    results_dir: PathBuf,
+}
+
+fn main() {
+    let args = Args::parse();
+    run(args);
+}
+
+fn run(args: Args) {
+    let mut cmd = Command::new(args.ctx.collector);
+    match &args.cmd {
+        PerfCommand::Eprintln => {
+            cmd.arg("profile_local").arg("eprintln");
+        }
+        PerfCommand::Samply => {
+            cmd.arg("profile_local").arg("samply");
+        }
+        PerfCommand::Cachegrind => {
+            cmd.arg("profile_local").arg("cachegrind");
+        }
+    }
+    if args.cmd.is_profiling() {
+        cmd.arg("--out-dir").arg(&args.ctx.results_dir);
+    }
+
+    if !args.opts.include.is_empty() {
+        cmd.arg("--include").arg(args.opts.include.join(","));
+    }
+    if !args.opts.profiles.is_empty() {
+        cmd.arg("--profiles")
+            .arg(args.opts.profiles.iter().map(|p| p.to_string()).collect::<Vec<_>>().join(","));
+    }
+    if !args.opts.scenarios.is_empty() {
+        cmd.arg("--scenarios")
+            .arg(args.opts.scenarios.iter().map(|p| p.to_string()).collect::<Vec<_>>().join(","));
+    }
+    cmd.arg(&args.ctx.compiler);
+
+    println!("Running `rustc-perf` using `{}`", args.ctx.compiler.display());
+
+    const MANIFEST_DIR: &str = env!("CARGO_MANIFEST_DIR");
+
+    let rustc_perf_dir = PathBuf::from(MANIFEST_DIR).join("../rustc-perf");
+
+    // We need to set the working directory to `src/tools/perf`, so that it can find the directory
+    // with compile-time benchmarks.
+    let cmd = cmd.current_dir(rustc_perf_dir);
+    cmd.status().expect("error while running rustc-perf collector");
+
+    if args.cmd.is_profiling() {
+        println!("You can find the results at `{}`", args.ctx.results_dir.display());
+    }
+}
diff --git a/src/tools/rustfmt/.github/workflows/integration.yml b/src/tools/rustfmt/.github/workflows/integration.yml
index 314ce0e84c6..f0dd0cf73bb 100644
--- a/src/tools/rustfmt/.github/workflows/integration.yml
+++ b/src/tools/rustfmt/.github/workflows/integration.yml
@@ -19,7 +19,6 @@ jobs:
       matrix:
         integration: [
           bitflags,
-          error-chain,
           log,
           mdbook,
           packed_simd,
diff --git a/src/tools/rustfmt/CHANGELOG.md b/src/tools/rustfmt/CHANGELOG.md
index ec4c682d2c4..89e90fb17dd 100644
--- a/src/tools/rustfmt/CHANGELOG.md
+++ b/src/tools/rustfmt/CHANGELOG.md
@@ -2,6 +2,99 @@
 
 ## [Unreleased]
 
+### Fixed
+
+- Fix an idempotency issue when rewriting where clauses in which rustfmt would continuously add a trailing comma `,` to the end of trailing line comments [#5941](https://github.com/rust-lang/rustfmt/issues/5941).
+- Prevent enum variant attributes from wrapping one character early when using `version=Two` [#5801](https://github.com/rust-lang/rustfmt/issues/5801)
+- Properly wrap macro matchers at the `max_width` when using `version=Two` and `format_macro_matchers=true` [#3805](https://github.com/rust-lang/rustfmt/issues/3805)
+- Prevent panic when formatting trait declaration with non [Unicode Normalization Form] C (NFC) identifiers [#6069](https://github.com/rust-lang/rustfmt/issues/6069)
+  ```rust
+  // The ó below is two codepoints, ASCII o followed by U+0301 COMBINING ACUTE ACCENT.
+  // It NFC-normalizes to ó, U+00F3 LATIN SMALL LETTER O WITH ACUTE.
+  trait Foó: Bar {}
+  ```
+  [unicode normalization form]: https://unicode.org/reports/tr15/
+- Ensure a space is added to a range expression, when the right hand side of the range expression is a binary expression that ends with a trailing period [#6059](https://github.com/rust-lang/rustfmt/issues/6059)
+  ```rust
+  let range = 3. / 2. ..4.;
+  ```
+- When using `version=Two`, comments in match arms that contain `=>` no longer prevent formatting [#5998](https://github.com/rust-lang/rustfmt/issues/5998)
+  ```rust
+  match a {
+      _ =>
+      // comment with =>
+      {
+          println!("A")
+      }
+  }
+  ```
+- Prevent panics when formatting input that contains the expanded form of `offset_of!` [#5885](https://github.com/rust-lang/rustfmt/issues/5885) [#6105](https://github.com/rust-lang/rustfmt/issues/6105)
+  ```rust
+  const _: () = builtin # offset_of(x, x);
+  ```
+- When using `version=Two` inner attributes in `match` expressions are correctly indented [#6147](https://github.com/rust-lang/rustfmt/issues/6147)
+  ```rust
+  pub fn main() {
+      match x {
+          #![attr1]
+          #![attr2]
+          _ => (),
+      }
+  }
+  ```
+- Output correct syntax for type ascription builtin [#6159](https://github.com/rust-lang/rustfmt/issues/6159)
+  ```rust
+  fn main() {
+      builtin # type_ascribe(10, usize)
+  }
+  ```
+- rustfmt no longer removes inner attributes from inline const blocks [#6158](https://github.com/rust-lang/rustfmt/issues/6158)
+  ```rust
+  fn main() {
+      const {
+          #![allow(clippy::assertions_on_constants)]
+
+          assert!(1 < 2);
+      }
+  }
+  ```
+- rustfmt no longer removes `safe` and `unsafe` keywords from static items in extern blocks.
+  This helps support [`#![feature(unsafe_extern_blocks)]`](https://github.com/rust-lang/rust/issues/123743) [#6204](https://github.com/rust-lang/rustfmt/pull/6204)
+  ```rust
+  #![feature(unsafe_extern_blocks)]
+
+  unsafe extern "C" {
+      safe static TEST1: i32;
+      unsafe static TEST2: i32;
+  }
+  ```
+
+
+### Changed
+
+- `hide_parse_errors` has been soft deprecated and it's been renamed to `show_parse_errors` [#5961](https://github.com/rust-lang/rustfmt/pull/5961).
+- The diff output produced by `rustfmt --check` is more compatable with editors that support navigating directly to line numbers [#5971](https://github.com/rust-lang/rustfmt/pull/5971)
+- When using `version=Two`, the `trace!` macro from the [log crate] is now formatted similarly to `debug!`, `info!`, `warn!`, and `error!` [#5987](https://github.com/rust-lang/rustfmt/issues/5987).
+
+  [log crate]: https://crates.io/crates/log
+
+
+### Added
+
+- `generated_marker_line_search_limit` is a new unstable configuration option that allows users to configure how many lines to search for an `@generated` marker when `format_generated_files=false` [#5658](https://github.com/rust-lang/rustfmt/issues/5658)
+
+
+### Misc
+
+- Updating `dirs 4.0.0 -> 5.0.1` and `cargo_metadata 0.15.4 -> 0.18.0` [#6033] (https://github.com/rust-lang/rustfmt/issues/6033)
+  - For reference, here's the [dirs v5 changelog](https://github.com/dirs-dev/dirs-rs/blob/main/README.md#5)
+- Updated [itertools v0.11 -> v0.12](https://github.com/rust-itertools/itertools/blob/v0.12.1/CHANGELOG.md#0120) [#6093](https://github.com/rust-lang/rustfmt/pull/6093)
+- Addressed clap deprecations output when running `cargo check --features clap/deprecated` [#6101](https://github.com/rust-lang/rustfmt/pull/6101)
+- Bumped bytecount `0.6.4` -> `0.6.8` to fix compilation issues with the `generic-simd` feature. See [bytecount#92] and [bytecount#93]
+
+  [bytecount#92]: https://github.com/llogiq/bytecount/pull/92
+  [bytecount#93]: https://github.com/llogiq/bytecount/pull/93
+- Replace the `lazy_static` dependency with `std::sync::OnceLock` [#6154](https://github.com/rust-lang/rustfmt/pull/6154)
 
 ## [1.7.0] 2023-10-22
 
@@ -27,7 +120,7 @@
   }
   ```
 - Prevent ICE when formatting `vec!{}` [#5735](https://github.com/rust-lang/rustfmt/issues/5735)
-- Prevent internal trailing whitespace error when formatting an empty `macro_rules!` defintion e.g. `macro_rules! foo {}` [#5882](https://github.com/rust-lang/rustfmt/issues/5882)
+- Prevent internal trailing whitespace error when formatting an empty `macro_rules!` definition e.g. `macro_rules! foo {}` [#5882](https://github.com/rust-lang/rustfmt/issues/5882)
 - Formatting doc comment lines that start with `.` or `)` won't be treated as ordered markdown lists because `.` or `)` must be preceded by a number to start an ordered markdown list [#5835](https://github.com/rust-lang/rustfmt/pull/5835)
 - Add parenthesis around closures when they're used as method receives, don't have a block body, and end with `.` [#4808](https://github.com/rust-lang/rustfmt/issues/4808)
   ```rust
@@ -184,7 +277,7 @@
 
 - Simplify the rustfmt help text by eliding the full path to the rustfmt binary path from the usage string when running `rustfmt --help` [#5214](https://github.com/rust-lang/rustfmt/issues/5214)
 
-- Bumped the version for serveral dependencies. Most notably `dirs` `v2.0.1` -> `v4.0.0`. This changed the global user config directory on macOS from `$HOME/Library/Preferences` to `$HOME/Library/Application Support` [#5237](https://github.com/rust-lang/rustfmt/pull/5237)
+- Bumped the version for several dependencies. Most notably `dirs` `v2.0.1` -> `v4.0.0`. This changed the global user config directory on macOS from `$HOME/Library/Preferences` to `$HOME/Library/Application Support` [#5237](https://github.com/rust-lang/rustfmt/pull/5237)
 
 ### Fixed
 
@@ -942,7 +1035,7 @@ from formatting an attribute #3665
 
 ### Fixed
 
-- Do not remove path disambiugator inside macro #3142
+- Do not remove path disambiguator inside macro #3142
 - Improve handling of Windows newlines #3141
 - Fix alignment of a struct's fields (`struct_field_align_threshold` option) with the Visual `indent_style` #3165
 - Fix a bug in formatting markdown lists within comments #3172
@@ -1031,7 +1124,7 @@ from formatting an attribute #3665
 
 ### Changed
 
-- Replace '--conifig-help' with '--config=help' cb10e06
+- Replace '--config-help' with '--config=help' cb10e06
 - Improve formatting of slice patterns #2912
 
 ### Fixed
@@ -1075,7 +1168,7 @@ from formatting an attribute #3665
 - Add max_width option for all heuristics c2ae39e
 - Add config option `format_macro_matchers` to format the metavariable matching patterns in macros 79c5ee8
 - Add config option `format_macro_bodies` to format the bodies of macros 79c5ee8
-- Format exitential type fc307ff
+- Format existential type fc307ff
 - Support raw identifiers in struct expressions f121b1a
 - Format Async block and async function 0b25f60
 
@@ -1131,7 +1224,7 @@ from formatting an attribute #3665
 
 ### Changed
 
-- Update rustc-ap-syntax to 128.0.0 and ustc-ap-rustc_target to 128.0.0 195395f
+- Update rustc-ap-syntax to 128.0.0 and rustc-ap-rustc_target to 128.0.0 195395f
 - Put operands on its own line when each fits in a single line f8439ce
 - Improve CLI options 55ac062 1869888 798bffb 4d9de48 eca7796 8396da1 5d9f5aa
 
@@ -1195,7 +1288,7 @@ from formatting an attribute #3665
 - Do not collapse block around expr with condition on match arm 5b9b7d5
 - Use vertical layout for complex attributes c77708f
 - Format array using heuristics for function calls 98c6f7b
-- Implement stable ordering for impl items with the the following item priority: type, const, macro, then method fa80ddf
+- Implement stable ordering for impl items with the following item priority: type, const, macro, then method fa80ddf
 - Reorder imports by default 164cf7d
 - Group `extern crate` by default 3a138a2
 - Make `error_on_line_overflow` false by default f146711
diff --git a/src/tools/rustfmt/Cargo.lock b/src/tools/rustfmt/Cargo.lock
index 8fcefa97489..2a1fffa50fe 100644
--- a/src/tools/rustfmt/Cargo.lock
+++ b/src/tools/rustfmt/Cargo.lock
@@ -98,12 +98,9 @@ dependencies = [
 
 [[package]]
 name = "bytecount"
-version = "0.6.4"
+version = "0.6.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad152d03a2c813c80bb94fedbf3a3f02b28f793e39e7c214c8a0bcc196343de7"
-dependencies = [
- "packed_simd",
-]
+checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce"
 
 [[package]]
 name = "camino"
@@ -125,9 +122,9 @@ dependencies = [
 
 [[package]]
 name = "cargo_metadata"
-version = "0.15.4"
+version = "0.18.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a"
+checksum = "fb9ac64500cc83ce4b9f8dafa78186aa008c8dea77a09b94cd307fd0cd5022a8"
 dependencies = [
  "camino",
  "cargo-platform",
@@ -217,9 +214,9 @@ checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499"
 
 [[package]]
 name = "dirs"
-version = "4.0.0"
+version = "5.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
+checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
 dependencies = [
  "dirs-sys",
 ]
@@ -236,13 +233,14 @@ dependencies = [
 
 [[package]]
 name = "dirs-sys"
-version = "0.3.7"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
+checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
 dependencies = [
  "libc",
+ "option-ext",
  "redox_users",
- "winapi",
+ "windows-sys",
 ]
 
 [[package]]
@@ -343,9 +341,9 @@ dependencies = [
 
 [[package]]
 name = "itertools"
-version = "0.10.3"
+version = "0.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
+checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
 dependencies = [
  "either",
 ]
@@ -369,12 +367,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5"
 
 [[package]]
-name = "libm"
-version = "0.2.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
-
-[[package]]
 name = "log"
 version = "0.4.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -409,36 +401,22 @@ dependencies = [
 ]
 
 [[package]]
-name = "num-traits"
-version = "0.2.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
-dependencies = [
- "autocfg",
- "libm",
-]
-
-[[package]]
 name = "once_cell"
 version = "1.17.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
 
 [[package]]
-name = "overload"
-version = "0.1.1"
+name = "option-ext"
+version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
+checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
 
 [[package]]
-name = "packed_simd"
-version = "0.3.9"
+name = "overload"
+version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f9f08af0c877571712e2e3e686ad79efad9657dbf0f7c3c8ba943ff6c38932d"
-dependencies = [
- "cfg-if",
- "num-traits",
-]
+checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
 
 [[package]]
 name = "pin-project-lite"
@@ -521,7 +499,7 @@ dependencies = [
 
 [[package]]
 name = "rustfmt-nightly"
-version = "1.7.0"
+version = "1.7.1"
 dependencies = [
  "annotate-snippets",
  "anyhow",
@@ -534,7 +512,6 @@ dependencies = [
  "getopts",
  "ignore",
  "itertools",
- "lazy_static",
  "regex",
  "rustfmt-config_proc_macro",
  "serde",
diff --git a/src/tools/rustfmt/Cargo.toml b/src/tools/rustfmt/Cargo.toml
index 032b9b54810..a16620ed99b 100644
--- a/src/tools/rustfmt/Cargo.toml
+++ b/src/tools/rustfmt/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 
 name = "rustfmt-nightly"
-version = "1.7.0"
+version = "1.7.1"
 description = "Tool to find and fix Rust formatting issues"
 repository = "https://github.com/rust-lang/rustfmt"
 readme = "README.md"
@@ -35,16 +35,15 @@ generic-simd = ["bytecount/generic-simd"]
 [dependencies]
 annotate-snippets = { version = "0.9", features = ["color"] }
 anyhow = "1.0"
-bytecount = "0.6.4"
-cargo_metadata = "0.15.4"
+bytecount = "0.6.8"
+cargo_metadata = "0.18"
 clap = { version = "4.4.2", features = ["derive"] }
 clap-cargo = "0.12.0"
 diff = "0.1"
-dirs = "4.0"
+dirs = "5.0"
 getopts = "0.2"
 ignore = "0.4"
-itertools = "0.11"
-lazy_static = "1.4"
+itertools = "0.12"
 regex = "1.7"
 serde = { version = "1.0.160", features = ["derive"] }
 serde_json = "1.0"
diff --git a/src/tools/rustfmt/Configurations.md b/src/tools/rustfmt/Configurations.md
index ac5747800b2..f52c2573154 100644
--- a/src/tools/rustfmt/Configurations.md
+++ b/src/tools/rustfmt/Configurations.md
@@ -1,6 +1,6 @@
 # Configuring Rustfmt
 
-Rustfmt is designed to be very configurable. You can create a TOML file called `rustfmt.toml` or `.rustfmt.toml`, place it in the project or any other parent directory and it will apply the options in that file. If none of these directories contain such a file, both your home directory and a directory called `rustfmt` in your [global config directory](https://docs.rs/dirs/4.0.0/dirs/fn.config_dir.html) (e.g. `.config/rustfmt/`) are checked as well.
+Rustfmt is designed to be very configurable. You can create a TOML file called `rustfmt.toml` or `.rustfmt.toml`, place it in the project or any other parent directory and it will apply the options in that file. If none of these directories contain such a file, both your home directory and a directory called `rustfmt` in your [global config directory](https://docs.rs/dirs/5.0.1/dirs/fn.config_dir.html) (e.g. `.config/rustfmt/`) are checked as well.
 
 A possible content of `rustfmt.toml` or `.rustfmt.toml` might look like this:
 
@@ -1050,8 +1050,8 @@ Max width for code snippets included in doc comments. Only used if [`format_code
 
 ## `format_generated_files`
 
-Format generated files. A file is considered generated
-if any of the first five lines contain a `@generated` comment marker.
+Format generated files. A file is considered generated if any of the first several lines contain a `@generated` comment marker. The number of lines to check is configured by `generated_marker_line_search_limit`.
+
 By default, generated files are reformatted, i. e. `@generated` marker is ignored.
 This option is currently ignored for stdin (`@generated` in stdin is ignored.)
 
@@ -1059,6 +1059,16 @@ This option is currently ignored for stdin (`@generated` in stdin is ignored.)
 - **Possible values**: `true`, `false`
 - **Stable**: No (tracking issue: [#5080](https://github.com/rust-lang/rustfmt/issues/5080))
 
+## `generated_marker_line_search_limit`
+
+Number of lines to check for a `@generated` pragma header, starting from the top of the file. Setting this value to `0` will treat all files as non-generated. When`format_generated_files` is `true`, this option has no effect.
+
+- **Default value**: `5`
+- **Possible values**: any positive integer
+- **Stable**: No (tracking issue: [#5080](https://github.com/rust-lang/rustfmt/issues/5080))
+
+See also [format_generated_files](#format_generated_files) link here.
+
 ## `format_macro_matchers`
 
 Format the metavariable matching patterns in macros.
@@ -1098,7 +1108,7 @@ See also [`format_macro_bodies`](#format_macro_bodies).
 
 ## `format_macro_bodies`
 
-Format the bodies of macros.
+Format the bodies of declarative macro definitions.
 
 - **Default value**: `true`
 - **Possible values**: `true`, `false`
@@ -1248,12 +1258,20 @@ Control the case of the letters in hexadecimal literal values
 
 ## `hide_parse_errors`
 
-Do not show parse errors if the parser failed to parse files.
+This option is deprecated and has been renamed to `show_parse_errors` to avoid confusion around the double negative default of `hide_parse_errors=false`.
 
 - **Default value**: `false`
 - **Possible values**: `true`, `false`
 - **Stable**: No (tracking issue: [#3390](https://github.com/rust-lang/rustfmt/issues/3390))
 
+## `show_parse_errors`
+
+Show parse errors if the parser failed to parse files.
+
+- **Default value**: `true`
+- **Possible values**: `true`, `false`
+- **Stable**: No (tracking issue: [#5977](https://github.com/rust-lang/rustfmt/issues/5977))
+
 ## `ignore`
 
 Skip formatting files and directories that match the specified pattern.
@@ -1288,6 +1306,15 @@ If you want to ignore every file under the directory where you put your rustfmt.
 ignore = ["/"]
 ```
 
+If you want to allow specific paths that would otherwise be ignored, prefix those paths with a `!`:
+
+```toml
+ignore = ["bar_dir/*", "!bar_dir/*/what.rs"]
+```
+
+In this case, all files under `bar_dir` will be ignored, except files like `bar_dir/sub/what.rs`
+or `bar_dir/another/what.rs`.
+
 ## `imports_indent`
 
 Indent style of imports
@@ -1655,7 +1682,7 @@ use core::slice;
 
 Controls whether arm bodies are wrapped in cases where the first line of the body cannot fit on the same line as the `=>` operator.
 
-The Style Guide requires that bodies are block wrapped by default if a line break is required after the `=>`, but this option can be used to disable that behavior to prevent wrapping arm bodies in that event, so long as the body does not contain multiple statements nor line comments.
+The Style Guide requires that bodies are block wrapped by default if a line break is required after the `=>`, but this option can be used to disable that behavior to prevent wrapping arm bodies in that event, so long as the body contains neither multiple statements nor line comments.
 
 - **Default value**: `true`
 - **Possible values**: `true`, `false`
diff --git a/src/tools/rustfmt/Contributing.md b/src/tools/rustfmt/Contributing.md
index 69a2c76369f..2f2ccfb175a 100644
--- a/src/tools/rustfmt/Contributing.md
+++ b/src/tools/rustfmt/Contributing.md
@@ -59,7 +59,7 @@ example, the `issue-1111.rs` test file is configured by the file
 ## Debugging
 
 Some `rewrite_*` methods use the `debug!` macro for printing useful information.
-These messages can be printed by using the environment variable `RUSTFMT_LOG=rustfmt=DEBUG`.
+These messages can be printed by using the environment variable `RUSTFMT_LOG=debug`.
 These traces can be helpful in understanding which part of the code was used
 and get a better grasp on the execution flow.
 
diff --git a/src/tools/rustfmt/Processes.md b/src/tools/rustfmt/Processes.md
index 61abc87eec9..64ef20a9bd7 100644
--- a/src/tools/rustfmt/Processes.md
+++ b/src/tools/rustfmt/Processes.md
@@ -16,7 +16,7 @@ In this Section, we describe how to stabilise an option of the rustfmt's configu
 Open a pull request that closes the tracking issue. The tracking issue is listed beside the option in `Configurations.md`.
 
 - Update the `Config` enum marking the option as stable.
-- Update the the `Configuration.md` file marking the option as stable.
+- Update the `Configuration.md` file marking the option as stable.
 - Update `CHANGELOG.md` marking the option as stable.
 
 ## After the stabilisation
diff --git a/src/tools/rustfmt/build.rs b/src/tools/rustfmt/build.rs
index e7b1e1b854c..9a8bb77a8ed 100644
--- a/src/tools/rustfmt/build.rs
+++ b/src/tools/rustfmt/build.rs
@@ -40,7 +40,7 @@ fn channel() -> String {
 
 fn commit_hash() -> Option<String> {
     Command::new("git")
-        .args(&["rev-parse", "--short", "HEAD"])
+        .args(["rev-parse", "--short", "HEAD"])
         .output()
         .ok()
         .and_then(|r| String::from_utf8(r.stdout).ok())
@@ -48,7 +48,7 @@ fn commit_hash() -> Option<String> {
 
 fn commit_date() -> Option<String> {
     Command::new("git")
-        .args(&["log", "-1", "--date=short", "--pretty=format:%cd"])
+        .args(["log", "-1", "--date=short", "--pretty=format:%cd"])
         .output()
         .ok()
         .and_then(|r| String::from_utf8(r.stdout).ok())
diff --git a/src/tools/rustfmt/check_diff/.gitignore b/src/tools/rustfmt/check_diff/.gitignore
new file mode 100644
index 00000000000..ea8c4bf7f35
--- /dev/null
+++ b/src/tools/rustfmt/check_diff/.gitignore
@@ -0,0 +1 @@
+/target
diff --git a/src/tools/rustfmt/check_diff/Cargo.lock b/src/tools/rustfmt/check_diff/Cargo.lock
new file mode 100644
index 00000000000..6716ccdf9a0
--- /dev/null
+++ b/src/tools/rustfmt/check_diff/Cargo.lock
@@ -0,0 +1,237 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "anstream"
+version = "0.6.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
+
+[[package]]
+name = "anstyle-parse"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19"
+dependencies = [
+ "anstyle",
+ "windows-sys",
+]
+
+[[package]]
+name = "check_diff"
+version = "0.1.0"
+dependencies = [
+ "clap",
+]
+
+[[package]]
+name = "clap"
+version = "4.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0"
+dependencies = [
+ "clap_builder",
+ "clap_derive",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "clap_lex",
+ "strsim",
+]
+
+[[package]]
+name = "clap_derive"
+version = "4.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
+
+[[package]]
+name = "colorchoice"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "syn"
+version = "2.0.66"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+
+[[package]]
+name = "utf8parse"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
+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",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
diff --git a/src/tools/rustfmt/check_diff/Cargo.toml b/src/tools/rustfmt/check_diff/Cargo.toml
new file mode 100644
index 00000000000..a1ed154481a
--- /dev/null
+++ b/src/tools/rustfmt/check_diff/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "check_diff"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+clap = { version = "4.4.2", features = ["derive"] }
diff --git a/src/tools/rustfmt/check_diff/src/main.rs b/src/tools/rustfmt/check_diff/src/main.rs
new file mode 100644
index 00000000000..6d07c1b0df6
--- /dev/null
+++ b/src/tools/rustfmt/check_diff/src/main.rs
@@ -0,0 +1,25 @@
+use clap::Parser;
+/// Inputs for the check_diff script
+#[derive(Parser)]
+struct CliInputs {
+    /// Git url of a rustfmt fork to compare against the latest master rustfmt
+    remote_repo_url: String,
+    /// Name of the feature branch on the forked repo
+    feature_branch: String,
+    /// Optional commit hash from the feature branch
+    #[arg(short, long)]
+    commit_hash: Option<String>,
+    /// Optional comma separated list of rustfmt config options to
+    /// pass when running the feature branch
+    #[arg(value_delimiter = ',', short, long, num_args = 1..)]
+    rustfmt_config: Option<Vec<String>>,
+}
+
+fn main() {
+    let args = CliInputs::parse();
+    println!(
+        "remote_repo_url: {:?}, feature_branch: {:?},
+        optional_commit_hash: {:?}, optional_rustfmt_config: {:?}",
+        args.remote_repo_url, args.feature_branch, args.commit_hash, args.rustfmt_config
+    );
+}
diff --git a/src/tools/rustfmt/ci/check_diff.sh b/src/tools/rustfmt/ci/check_diff.sh
index 50c58b1f492..2a29cb138ef 100755
--- a/src/tools/rustfmt/ci/check_diff.sh
+++ b/src/tools/rustfmt/ci/check_diff.sh
@@ -2,9 +2,6 @@
 
 set -e
 
-# https://github.com/rust-lang/rustfmt/issues/5675
-export LD_LIBRARY_PATH=$(rustc --print sysroot)/lib:$LD_LIBRARY_PATH
-
 function print_usage() {
     echo "usage check_diff REMOTE_REPO FEATURE_BRANCH [COMMIT_HASH] [OPTIONAL_RUSTFMT_CONFIGS]"
 }
@@ -31,7 +28,7 @@ function clone_repo() {
     GIT_TERMINAL_PROMPT=0 git clone --quiet $1 --depth 1 $2 && cd $2
 }
 
-# Initialize Git submoduels for the repo.
+# Initialize Git submodules for the repo.
 #
 # Parameters
 # $1: list of directories to initialize
@@ -46,7 +43,7 @@ function init_submodules() {
 # $2: Output file path for the diff
 # $3: Any additional configuration options to pass to rustfmt
 #
-# Globlas:
+# Globals:
 # $OPTIONAL_RUSTFMT_CONFIGS: Optional configs passed to the script from $4
 function create_diff() {
     local config;
@@ -67,7 +64,7 @@ function create_diff() {
 # Parameters
 # $1: Name of the repository (used for logging)
 #
-# Globlas:
+# Globals:
 # $RUSFMT_BIN: Path to the rustfmt master binary. Created when running `compile_rustfmt`
 # $FEATURE_BIN: Path to the rustfmt feature binary. Created when running `compile_rustfmt`
 # $OPTIONAL_RUSTFMT_CONFIGS: Optional configs passed to the script from $4
@@ -90,7 +87,7 @@ function check_diff() {
     )
 
     if [ -z "$diff" ]; then
-        echo "no diff detected between rustfmt and the feture branch"
+        echo "no diff detected between rustfmt and the feature branch"
         return 0
     else
         echo "$diff"
@@ -104,7 +101,7 @@ function check_diff() {
 # Parameters:
 # $1: Directory where rustfmt will be cloned
 #
-# Globlas:
+# Globals:
 # $REMOTE_REPO: Clone URL to the rustfmt fork that we want to test
 # $FEATURE_BRANCH: Name of the feature branch
 # $OPTIONAL_COMMIT_HASH: Optional commit hash that will be checked out if provided
@@ -114,15 +111,42 @@ function compile_rustfmt() {
     git remote add feature $REMOTE_REPO
     git fetch feature $FEATURE_BRANCH
 
-    cargo build --release --bin rustfmt && cp target/release/rustfmt $1/rustfmt
+    CARGO_VERSION=$(cargo --version)
+    echo -e "\ncompiling with $CARGO_VERSION\n"
+
+    # Because we're building standalone binaries we need to set `LD_LIBRARY_PATH` so each
+    # binary can find it's runtime dependencies. See https://github.com/rust-lang/rustfmt/issues/5675
+    # This will prepend the `LD_LIBRARY_PATH` for the master rustfmt binary
+    export LD_LIBRARY_PATH=$(rustc --print sysroot)/lib:$LD_LIBRARY_PATH
+
+    echo "Building rustfmt from src"
+    cargo build -q --release --bin rustfmt && cp target/release/rustfmt $1/rustfmt
+
     if [ -z "$OPTIONAL_COMMIT_HASH" ] || [ "$FEATURE_BRANCH" = "$OPTIONAL_COMMIT_HASH" ]; then
         git switch $FEATURE_BRANCH
     else
         git switch $OPTIONAL_COMMIT_HASH --detach
     fi
-    cargo build --release --bin rustfmt && cp target/release/rustfmt $1/feature_rustfmt
+
+    # This will prepend the `LD_LIBRARY_PATH` for the feature branch rustfmt binary.
+    # In most cases the `LD_LIBRARY_PATH` should be the same for both rustfmt binaries that we build
+    # in `compile_rustfmt`, however, there are scenarios where each binary has different runtime
+    # dependencies. For example, during subtree syncs we bump the nightly toolchain required to build
+    # rustfmt, and therefore the feature branch relies on a newer set of runtime dependencies.
+    export LD_LIBRARY_PATH=$(rustc --print sysroot)/lib:$LD_LIBRARY_PATH
+
+    echo "Building feature rustfmt from src"
+    cargo build -q --release --bin rustfmt && cp target/release/rustfmt $1/feature_rustfmt
+
+    echo -e "\nRuntime dependencies for rustfmt -- LD_LIBRARY_PATH: $LD_LIBRARY_PATH"
+
     RUSFMT_BIN=$1/rustfmt
+    RUSTFMT_VERSION=$($RUSFMT_BIN --version)
+    echo -e "\nRUSFMT_BIN $RUSTFMT_VERSION\n"
+
     FEATURE_BIN=$1/feature_rustfmt
+    FEATURE_VERSION=$($FEATURE_BIN --version)
+    echo -e "FEATURE_BIN $FEATURE_VERSION\n"
 }
 
 # Check the diff for running rustfmt and the feature branch on all the .rs files in the repo.
@@ -155,7 +179,7 @@ function check_repo() {
     STATUSES+=($?)
     set -e
 
-    echo "removing tmp_dir $tmp_dir"
+    echo -e "removing tmp_dir $tmp_dir\n\n"
     rm -rf $tmp_dir
     cd $WORKDIR
 }
diff --git a/src/tools/rustfmt/ci/integration.sh b/src/tools/rustfmt/ci/integration.sh
index 19d502bc5c7..ea96e4be130 100755
--- a/src/tools/rustfmt/ci/integration.sh
+++ b/src/tools/rustfmt/ci/integration.sh
@@ -104,7 +104,7 @@ case ${INTEGRATION} in
         check_fmt_with_all_tests
         cd -
         ;;
-    error-chain | tempdir)
+    tempdir)
         git clone --depth=1 https://github.com/rust-lang-deprecated/${INTEGRATION}.git
         cd ${INTEGRATION}
         show_head
diff --git a/src/tools/rustfmt/config_proc_macro/src/attrs.rs b/src/tools/rustfmt/config_proc_macro/src/attrs.rs
index d8de9aae088..e7534b813d7 100644
--- a/src/tools/rustfmt/config_proc_macro/src/attrs.rs
+++ b/src/tools/rustfmt/config_proc_macro/src/attrs.rs
@@ -68,7 +68,11 @@ fn get_name_value_str_lit(attr: &syn::Attribute, name: &str) -> Option<String> {
     match &attr.meta {
         syn::Meta::NameValue(syn::MetaNameValue {
             path,
-            value: syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Str(lit_str), .. }),
+            value:
+                syn::Expr::Lit(syn::ExprLit {
+                    lit: syn::Lit::Str(lit_str),
+                    ..
+                }),
             ..
         }) if path.is_ident(name) => Some(lit_str.value()),
         _ => None,
diff --git a/src/tools/rustfmt/docs/index.html b/src/tools/rustfmt/docs/index.html
index ee0339bc50d..5e588d1db54 100644
--- a/src/tools/rustfmt/docs/index.html
+++ b/src/tools/rustfmt/docs/index.html
@@ -3,13 +3,33 @@
     <head>
       <meta name="viewport" content="width=device-width">
       <title>Rustfmt</title>
-      <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/3.0.1/github-markdown.css" />
-      <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.0.0/styles/github-gist.min.css">
-      <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
-      <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
+      <link rel="stylesheet"
+            href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/3.0.1/github-markdown.min.css"
+            integrity="sha512-7e0rszTy0dKTIgYzCeBXpmycq0EOkwAvxZ0dv/LAtQfcXWCoaRhzs+v2Mn6of3jImxPazbYxiK0kpE/7wZ/UQA=="
+            crossorigin="anonymous"
+            referrerpolicy="no-referrer" />
+      <link rel="stylesheet"
+            href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.0.0/styles/github-gist.min.css"
+            integrity="sha512-od7JLoOTxM8w/HSKGzP9Kexc20K9p/M2zxSWsd7H1e4Ctf+8SQFtCWEZnW5u6ul5ehSECa5QmOk9ju2nQMmlVA=="
+            crossorigin="anonymous"
+            referrerpolicy="no-referrer" />
+      <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.2/marked.min.js"
+              integrity="sha512-xeUh+KxNyTufZOje++oQHstlMQ8/rpyzPuM+gjMFYK3z5ILJGE7l2NvYL+XfliKURMpBIKKp1XoPN/qswlSMFA=="
+              crossorigin="anonymous" 
+              referrerpolicy="no-referrer"></script>
+      <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js"
+              integrity="sha512-PwQ5+jgXxxprNGc80ycHE3spgj6TuDieHe/yTkbEJ+U5aol7dTupi/4VbwHHzlQVW77Vb0GLOIsiYigHgC5vcg=="
+              crossorigin="anonymous"
+              referrerpolicy="no-referrer"></script>
+      <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.0.0/highlight.min.js"
+              integrity="sha512-av6ZR84Ldk6j29DMhf6v0cssEhow1VROFLoKbX7wrvzZB++/nV8m0jXbYeWcHPEzSNONImx6zwBskCUT9AQidA=="
+              crossorigin="anonymous"
+              referrerpolicy="no-referrer"></script>
+      <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"
+              integrity="sha512-3BBFWr73Xrf8GRjO+0pl0cbVwESBvg3ovnuCXpoqOkC/mkt/hTkFtutUPrwRz8eLySYvy5v1daulkyUZYvH8jw=="
+              crossorigin="anonymous"
+              referrerpolicy="no-referrer"></script>
       <script src="https://unpkg.com/vue-async-computed@3.8.1"></script>
-      <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.0.0/highlight.min.js"></script>
-      <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>
       <style>
         @media (max-width: 767px) {
           .markdown-body {
diff --git a/src/tools/rustfmt/intellij.md b/src/tools/rustfmt/intellij.md
index 6a711c0171a..70170df388f 100644
--- a/src/tools/rustfmt/intellij.md
+++ b/src/tools/rustfmt/intellij.md
@@ -20,7 +20,7 @@
 - Open Rustfmt settings (File → Settings → Languages & Frameworks → Rust → Rustfmt) and enable "Run rustfmt on Save"
   ![run_rustfmt_on_save](https://user-images.githubusercontent.com/6505554/83944610-3468f380-a81e-11ea-9c34-0cbd18dd4969.png)
 
-- IntellJ uses autosave, so now your files will always be formatted according to rustfmt. Alternatively you can use Ctrl+S to reformat file manually
+- IntelliJ uses autosave, so now your files will always be formatted according to rustfmt. Alternatively you can use Ctrl+S to reformat file manually
 
 ### Bind shortcut to "Reformat File with Rustfmt" action
 
diff --git a/src/tools/rustfmt/rust-toolchain b/src/tools/rustfmt/rust-toolchain
index 0057e2f370a..25e3961d32a 100644
--- a/src/tools/rustfmt/rust-toolchain
+++ b/src/tools/rustfmt/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2023-10-22"
+channel = "nightly-2024-06-13"
 components = ["llvm-tools", "rustc-dev"]
diff --git a/src/tools/rustfmt/src/attr.rs b/src/tools/rustfmt/src/attr.rs
index 83f59837d44..433b9256202 100644
--- a/src/tools/rustfmt/src/attr.rs
+++ b/src/tools/rustfmt/src/attr.rs
@@ -353,10 +353,18 @@ impl Rewrite for ast::Attribute {
 
                 // 1 = `[`
                 let shape = shape.offset_left(prefix.len() + 1)?;
-                Some(
-                    meta.rewrite(context, shape)
-                        .map_or_else(|| snippet.to_owned(), |rw| format!("{}[{}]", prefix, rw)),
-                )
+                Some(meta.rewrite(context, shape).map_or_else(
+                    || snippet.to_owned(),
+                    |rw| match &self.kind {
+                        ast::AttrKind::Normal(normal_attr) => match normal_attr.item.unsafety {
+                            // For #![feature(unsafe_attributes)]
+                            // See https://github.com/rust-lang/rust/issues/123757
+                            ast::Safety::Unsafe(_) => format!("{}[unsafe({})]", prefix, rw),
+                            _ => format!("{}[{}]", prefix, rw),
+                        },
+                        _ => format!("{}[{}]", prefix, rw),
+                    },
+                ))
             } else {
                 Some(snippet.to_owned())
             }
diff --git a/src/tools/rustfmt/src/bin/main.rs b/src/tools/rustfmt/src/bin/main.rs
index 6f564083656..88281d296be 100644
--- a/src/tools/rustfmt/src/bin/main.rs
+++ b/src/tools/rustfmt/src/bin/main.rs
@@ -387,16 +387,11 @@ fn format_and_emit_report<T: Write>(session: &mut Session<'_, T>, input: Input)
 }
 
 fn should_print_with_colors<T: Write>(session: &mut Session<'_, T>) -> bool {
-    match term::stderr() {
-        Some(ref t)
-            if session.config.color().use_colored_tty()
-                && t.supports_color()
-                && t.supports_attr(term::Attr::Bold) =>
-        {
-            true
-        }
-        _ => false,
-    }
+    term::stderr().is_some_and(|t| {
+        session.config.color().use_colored_tty()
+            && t.supports_color()
+            && t.supports_attr(term::Attr::Bold)
+    })
 }
 
 fn print_usage_to_stdout(opts: &Options, reason: &str) {
@@ -445,7 +440,7 @@ fn print_version() {
 fn determine_operation(matches: &Matches) -> Result<Operation, OperationError> {
     if matches.opt_present("h") {
         let topic = matches.opt_str("h");
-        if topic == None {
+        if topic.is_none() {
             return Ok(Operation::Help(HelpOp::None));
         } else if topic == Some("config".to_owned()) {
             return Ok(Operation::Help(HelpOp::Config));
diff --git a/src/tools/rustfmt/src/cargo-fmt/main.rs b/src/tools/rustfmt/src/cargo-fmt/main.rs
index a1ad1aafac4..eedb43defb9 100644
--- a/src/tools/rustfmt/src/cargo-fmt/main.rs
+++ b/src/tools/rustfmt/src/cargo-fmt/main.rs
@@ -61,7 +61,7 @@ pub struct Opts {
 
     /// Options passed to rustfmt
     // 'raw = true' to make `--` explicit.
-    #[arg(name = "rustfmt_options", raw = true)]
+    #[arg(id = "rustfmt_options", raw = true)]
     rustfmt_options: Vec<String>,
 
     /// Format all packages, and also their local path-based dependencies
@@ -209,9 +209,8 @@ fn convert_message_format_to_rustfmt_args(
 fn print_usage_to_stderr(reason: &str) {
     eprintln!("{reason}");
     let app = Opts::command();
-    app.after_help("")
-        .write_help(&mut io::stderr())
-        .expect("failed to write to stderr");
+    let help = app.after_help("").render_help();
+    eprintln!("{help}");
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -507,7 +506,7 @@ fn run_rustfmt(
         let mut command = rustfmt_command()
             .stdout(stdout)
             .args(files)
-            .args(&["--edition", edition.as_str()])
+            .args(["--edition", edition.as_str()])
             .args(fmt_args)
             .spawn()
             .map_err(|e| match e.kind() {
diff --git a/src/tools/rustfmt/src/cargo-fmt/test/mod.rs b/src/tools/rustfmt/src/cargo-fmt/test/mod.rs
index 696326e4f94..255e0d679d4 100644
--- a/src/tools/rustfmt/src/cargo-fmt/test/mod.rs
+++ b/src/tools/rustfmt/src/cargo-fmt/test/mod.rs
@@ -20,7 +20,7 @@ fn default_options() {
 
 #[test]
 fn good_options() {
-    let o = Opts::parse_from(&[
+    let o = Opts::parse_from([
         "test",
         "-q",
         "-p",
@@ -48,7 +48,7 @@ fn good_options() {
 fn unexpected_option() {
     assert!(
         Opts::command()
-            .try_get_matches_from(&["test", "unexpected"])
+            .try_get_matches_from(["test", "unexpected"])
             .is_err()
     );
 }
@@ -57,7 +57,7 @@ fn unexpected_option() {
 fn unexpected_flag() {
     assert!(
         Opts::command()
-            .try_get_matches_from(&["test", "--flag"])
+            .try_get_matches_from(["test", "--flag"])
             .is_err()
     );
 }
@@ -66,19 +66,19 @@ fn unexpected_flag() {
 fn mandatory_separator() {
     assert!(
         Opts::command()
-            .try_get_matches_from(&["test", "--emit"])
+            .try_get_matches_from(["test", "--emit"])
             .is_err()
     );
     assert!(
         Opts::command()
-            .try_get_matches_from(&["test", "--", "--emit"])
+            .try_get_matches_from(["test", "--", "--emit"])
             .is_ok()
     );
 }
 
 #[test]
 fn multiple_packages_one_by_one() {
-    let o = Opts::parse_from(&[
+    let o = Opts::parse_from([
         "test",
         "-p",
         "package1",
@@ -92,7 +92,7 @@ fn multiple_packages_one_by_one() {
 
 #[test]
 fn multiple_packages_grouped() {
-    let o = Opts::parse_from(&[
+    let o = Opts::parse_from([
         "test",
         "--package",
         "package1",
@@ -108,7 +108,7 @@ fn multiple_packages_grouped() {
 fn empty_packages_1() {
     assert!(
         Opts::command()
-            .try_get_matches_from(&["test", "-p"])
+            .try_get_matches_from(["test", "-p"])
             .is_err()
     );
 }
@@ -117,7 +117,7 @@ fn empty_packages_1() {
 fn empty_packages_2() {
     assert!(
         Opts::command()
-            .try_get_matches_from(&["test", "-p", "--", "--check"])
+            .try_get_matches_from(["test", "-p", "--", "--check"])
             .is_err()
     );
 }
@@ -126,7 +126,7 @@ fn empty_packages_2() {
 fn empty_packages_3() {
     assert!(
         Opts::command()
-            .try_get_matches_from(&["test", "-p", "--verbose"])
+            .try_get_matches_from(["test", "-p", "--verbose"])
             .is_err()
     );
 }
@@ -135,7 +135,7 @@ fn empty_packages_3() {
 fn empty_packages_4() {
     assert!(
         Opts::command()
-            .try_get_matches_from(&["test", "-p", "--check"])
+            .try_get_matches_from(["test", "-p", "--check"])
             .is_err()
     );
 }
diff --git a/src/tools/rustfmt/src/comment.rs b/src/tools/rustfmt/src/comment.rs
index 7d1b0384431..24a5a1be2c3 100644
--- a/src/tools/rustfmt/src/comment.rs
+++ b/src/tools/rustfmt/src/comment.rs
@@ -3,8 +3,6 @@
 use std::{borrow::Cow, iter};
 
 use itertools::{multipeek, MultiPeek};
-use lazy_static::lazy_static;
-use regex::Regex;
 use rustc_span::Span;
 
 use crate::config::Config;
@@ -17,17 +15,6 @@ use crate::utils::{
 };
 use crate::{ErrorKind, FormattingError};
 
-lazy_static! {
-    /// A regex matching reference doc links.
-    ///
-    /// ```markdown
-    /// /// An [example].
-    /// ///
-    /// /// [example]: this::is::a::link
-    /// ```
-    static ref REFERENCE_LINK_URL: Regex = Regex::new(r"^\[.+\]\s?:").unwrap();
-}
-
 fn is_custom_comment(comment: &str) -> bool {
     if !comment.starts_with("//") {
         false
@@ -173,10 +160,7 @@ pub(crate) fn combine_strs_with_missing_comments(
 ) -> Option<String> {
     trace!(
         "combine_strs_with_missing_comments `{}` `{}` {:?} {:?}",
-        prev_str,
-        next_str,
-        span,
-        shape
+        prev_str, next_str, span, shape
     );
 
     let mut result =
@@ -208,7 +192,7 @@ pub(crate) fn combine_strs_with_missing_comments(
 
     // We have a missing comment between the first expression and the second expression.
 
-    // Peek the the original source code and find out whether there is a newline between the first
+    // Peek the original source code and find out whether there is a newline between the first
     // expression and the second expression or the missing comment. We will preserve the original
     // layout whenever possible.
     let original_snippet = context.snippet(span);
@@ -506,7 +490,7 @@ impl ItemizedBlock {
         let mut line_start = " ".repeat(indent);
 
         // Markdown blockquote start with a "> "
-        if line.trim_start().starts_with(">") {
+        if line.trim_start().starts_with('>') {
             // remove the original +2 indent because there might be multiple nested block quotes
             // and it's easier to reason about the final indent by just taking the length
             // of the new line_start. We update the indent because it effects the max width
@@ -657,7 +641,7 @@ impl<'a> CommentRewrite<'a> {
         while let Some(line) = iter.next() {
             result.push_str(line);
             result.push_str(match iter.peek() {
-                Some(next_line) if next_line.is_empty() => sep.trim_end(),
+                Some(&"") => sep.trim_end(),
                 Some(..) => sep,
                 None => "",
             });
@@ -666,7 +650,7 @@ impl<'a> CommentRewrite<'a> {
     }
 
     /// Check if any characters were written to the result buffer after the start of the comment.
-    /// when calling [`CommentRewrite::new()`] the result buffer is initiazlied with the opening
+    /// when calling [`CommentRewrite::new()`] the result buffer is initialized with the opening
     /// characters for the comment.
     fn buffer_contains_comment(&self) -> bool {
         // if self.result.len() < self.opener.len() then an empty comment is in the buffer
@@ -839,7 +823,7 @@ impl<'a> CommentRewrite<'a> {
             }
         }
 
-        let is_markdown_header_doc_comment = is_doc_comment && line.starts_with("#");
+        let is_markdown_header_doc_comment = is_doc_comment && line.starts_with('#');
 
         // We only want to wrap the comment if:
         // 1) wrap_comments = true is configured
@@ -979,12 +963,21 @@ fn trim_custom_comment_prefix(s: &str) -> String {
 
 /// Returns `true` if the given string MAY include URLs or alike.
 fn has_url(s: &str) -> bool {
+    // A regex matching reference doc links.
+    //
+    // ```markdown
+    // /// An [example].
+    // ///
+    // /// [example]: this::is::a::link
+    // ```
+    let reference_link_url = static_regex!(r"^\[.+\]\s?:");
+
     // This function may return false positive, but should get its job done in most cases.
     s.contains("https://")
         || s.contains("http://")
         || s.contains("ftp://")
         || s.contains("file://")
-        || REFERENCE_LINK_URL.is_match(s)
+        || reference_link_url.is_match(s)
 }
 
 /// Returns true if the given string may be part of a Markdown table.
@@ -1263,15 +1256,15 @@ pub(crate) enum FullCodeCharKind {
     InComment,
     /// Last character of a comment, '\n' for a line comment, '/' for a block comment.
     EndComment,
-    /// Start of a mutlitine string inside a comment
+    /// Start of a multiline string inside a comment
     StartStringCommented,
-    /// End of a mutlitine string inside a comment
+    /// End of a multiline string inside a comment
     EndStringCommented,
     /// Inside a commented string
     InStringCommented,
-    /// Start of a mutlitine string
+    /// Start of a multiline string
     StartString,
-    /// End of a mutlitine string
+    /// End of a multiline string
     EndString,
     /// Inside a string.
     InString,
@@ -1764,7 +1757,7 @@ fn changed_comment_content(orig: &str, new: &str) -> bool {
     let code_comment_content = |code| {
         let slices = UngroupedCommentCodeSlices::new(code);
         slices
-            .filter(|&(ref kind, _, _)| *kind == CodeCharKind::Comment)
+            .filter(|(kind, _, _)| *kind == CodeCharKind::Comment)
             .flat_map(|(_, _, s)| CommentReducer::new(s))
     };
     let res = code_comment_content(orig).ne(code_comment_content(new));
diff --git a/src/tools/rustfmt/src/config/config_type.rs b/src/tools/rustfmt/src/config/config_type.rs
index feb452d7235..f7cff1a1729 100644
--- a/src/tools/rustfmt/src/config/config_type.rs
+++ b/src/tools/rustfmt/src/config/config_type.rs
@@ -66,7 +66,7 @@ impl ConfigType for IgnoreList {
 }
 
 macro_rules! create_config {
-    // Options passed in to the macro.
+    // Options passed into the macro.
     //
     // - $i: the ident name of the option
     // - $ty: the type of the option value
@@ -129,6 +129,7 @@ macro_rules! create_config {
                     | "chain_width" => self.0.set_heuristics(),
                     "merge_imports" => self.0.set_merge_imports(),
                     "fn_args_layout" => self.0.set_fn_args_layout(),
+                    "hide_parse_errors" => self.0.set_hide_parse_errors(),
                     &_ => (),
                 }
             }
@@ -184,6 +185,7 @@ macro_rules! create_config {
                 self.set_ignore(dir);
                 self.set_merge_imports();
                 self.set_fn_args_layout();
+                self.set_hide_parse_errors();
                 self
             }
 
@@ -278,19 +280,21 @@ macro_rules! create_config {
                     | "chain_width" => self.set_heuristics(),
                     "merge_imports" => self.set_merge_imports(),
                     "fn_args_layout" => self.set_fn_args_layout(),
+                    "hide_parse_errors" => self.set_hide_parse_errors(),
                     &_ => (),
                 }
             }
 
             #[allow(unreachable_pub)]
             pub fn is_hidden_option(name: &str) -> bool {
-                const HIDE_OPTIONS: [&str; 6] = [
+                const HIDE_OPTIONS: [&str; 7] = [
                     "verbose",
                     "verbose_diff",
                     "file_lines",
                     "width_heuristics",
                     "merge_imports",
-                    "fn_args_layout"
+                    "fn_args_layout",
+                    "hide_parse_errors"
                 ];
                 HIDE_OPTIONS.contains(&name)
             }
@@ -461,6 +465,18 @@ macro_rules! create_config {
                 }
             }
 
+            fn set_hide_parse_errors(&mut self) {
+                if self.was_set().hide_parse_errors() {
+                    eprintln!(
+                        "Warning: the `hide_parse_errors` option is deprecated. \
+                        Use `show_parse_errors` instead"
+                    );
+                    if !self.was_set().show_parse_errors() {
+                        self.show_parse_errors.2 = self.hide_parse_errors();
+                    }
+                }
+            }
+
             #[allow(unreachable_pub)]
             /// Returns `true` if the config key was explicitly set and is the default value.
             pub fn is_default(&self, key: &str) -> bool {
diff --git a/src/tools/rustfmt/src/config/mod.rs b/src/tools/rustfmt/src/config/mod.rs
index 9d454137b2c..9484b2e5829 100644
--- a/src/tools/rustfmt/src/config/mod.rs
+++ b/src/tools/rustfmt/src/config/mod.rs
@@ -26,6 +26,7 @@ pub(crate) mod file_lines;
 #[allow(unreachable_pub)]
 pub(crate) mod lists;
 pub(crate) mod macro_names;
+pub(crate) mod style_edition;
 
 // This macro defines configuration options used in rustfmt. Each option
 // is defined as follows:
@@ -73,7 +74,7 @@ create_config! {
     format_strings: bool, false, false, "Format string literals where necessary";
     format_macro_matchers: bool, false, false,
         "Format the metavariable matching patterns in macros";
-    format_macro_bodies: bool, true, false, "Format the bodies of macros";
+    format_macro_bodies: bool, true, false, "Format the bodies of declarative macro definitions";
     skip_macro_invocations: MacroSelectors, MacroSelectors::default(), false,
         "Skip formatting the bodies of macros invoked with the following names.";
     hex_literal_case: HexLiteralCase, HexLiteralCase::Preserve, false,
@@ -150,6 +151,8 @@ create_config! {
         "Write an item and its attribute on the same line \
         if their combined width is below a threshold";
     format_generated_files: bool, true, false, "Format generated files";
+    generated_marker_line_search_limit: usize, 5, false, "Number of lines to check for a \
+        `@generated` marker when `format_generated_files` is enabled";
 
     // Options that can change the source code beyond whitespace/blocks (somewhat linty things)
     merge_derives: bool, true, true, "Merge multiple `#[derive(...)]` into a single one";
@@ -168,7 +171,8 @@ create_config! {
             "Enables unstable features. Only available on nightly channel";
     disable_all_formatting: bool, false, true, "Don't reformat anything";
     skip_children: bool, false, false, "Don't reformat out of line modules";
-    hide_parse_errors: bool, false, false, "Hide errors from the parser";
+    hide_parse_errors: bool, false, false, "(deprecated: use show_parse_errors instead)";
+    show_parse_errors: bool, true, false, "Show errors from the parser (unstable)";
     error_on_line_overflow: bool, false, false, "Error if unable to get all lines within max_width";
     error_on_unformatted: bool, false, false,
         "Error if unable to get comments or string literals within max_width, \
@@ -203,6 +207,7 @@ impl PartialConfig {
         cloned.print_misformatted_file_names = None;
         cloned.merge_imports = None;
         cloned.fn_args_layout = None;
+        cloned.hide_parse_errors = None;
 
         ::toml::to_string(&cloned).map_err(ToTomlError)
     }
@@ -282,7 +287,7 @@ impl Config {
                 }
             }
 
-            // If none was found ther either, check in the user's configuration directory.
+            // If none was found there either, check in the user's configuration directory.
             if let Some(mut config_dir) = dirs::config_dir() {
                 config_dir.push("rustfmt");
                 if let Some(path) = get_toml_path(&config_dir)? {
@@ -455,6 +460,13 @@ mod test {
             fn_params_layout: Density, Density::Tall, true,
                 "Control the layout of parameters in a function signatures.";
 
+            // hide_parse_errors renamed to show_parse_errors
+            hide_parse_errors: bool, false, false,
+                "(deprecated: use show_parse_errors instead)";
+            show_parse_errors: bool, true, false,
+                "Show errors from the parser (unstable)";
+
+
             // Width Heuristics
             use_small_heuristics: Heuristics, Heuristics::Default, true,
                 "Whether to use different formatting for items and \
@@ -670,6 +682,7 @@ edition = "2015"
 version = "One"
 inline_attribute_width = 0
 format_generated_files = true
+generated_marker_line_search_limit = 5
 merge_derives = true
 use_try_shorthand = false
 use_field_init_shorthand = false
@@ -680,7 +693,7 @@ required_version = "{}"
 unstable_features = false
 disable_all_formatting = false
 skip_children = false
-hide_parse_errors = false
+show_parse_errors = true
 error_on_line_overflow = false
 error_on_unformatted = false
 ignore = []
diff --git a/src/tools/rustfmt/src/config/options.rs b/src/tools/rustfmt/src/config/options.rs
index 03fd91eb10f..3c5c713a33a 100644
--- a/src/tools/rustfmt/src/config/options.rs
+++ b/src/tools/rustfmt/src/config/options.rs
@@ -191,7 +191,7 @@ pub enum Color {
 pub enum Version {
     /// 1.x.y. When specified, rustfmt will format in the same style as 1.0.0.
     One,
-    /// 2.x.y. When specified, rustfmt will format in the the latest style.
+    /// 2.x.y. When specified, rustfmt will format in the latest style.
     Two,
 }
 
@@ -416,7 +416,7 @@ pub trait CliOptions {
     fn config_path(&self) -> Option<&Path>;
 }
 
-/// The edition of the syntax and semntics of code (RFC 2052).
+/// The edition of the syntax and semantics of code (RFC 2052).
 #[config_type]
 pub enum Edition {
     #[value = "2015"]
@@ -470,3 +470,27 @@ pub enum MatchArmLeadingPipe {
     /// Preserve any existing leading pipes
     Preserve,
 }
+
+/// Defines the default values for each config according to [the style guide].
+/// rustfmt output may differ between style editions.
+///
+/// [the style guide]: https://doc.rust-lang.org/nightly/style-guide/
+#[config_type]
+pub enum StyleEdition {
+    #[value = "2015"]
+    #[doc_hint = "2015"]
+    /// [Edition 2015]()
+    Edition2015,
+    #[value = "2018"]
+    #[doc_hint = "2018"]
+    /// [Edition 2018]()
+    Edition2018,
+    #[value = "2021"]
+    #[doc_hint = "2021"]
+    /// [Edition 2021]()
+    Edition2021,
+    #[value = "2024"]
+    #[doc_hint = "2024"]
+    /// [Edition 2024]().
+    Edition2024,
+}
diff --git a/src/tools/rustfmt/src/config/style_edition.rs b/src/tools/rustfmt/src/config/style_edition.rs
new file mode 100644
index 00000000000..7b3ea3bc119
--- /dev/null
+++ b/src/tools/rustfmt/src/config/style_edition.rs
@@ -0,0 +1,70 @@
+use crate::config::StyleEdition;
+
+/// Defines the default value for the given style edition
+#[allow(dead_code)]
+pub(crate) trait StyleEditionDefault {
+    type ConfigType;
+    fn style_edition_default(style_edition: StyleEdition) -> Self::ConfigType;
+}
+
+/// macro to help implement `StyleEditionDefault` for config options
+#[macro_export]
+macro_rules! style_edition_default {
+    ($ty:ident, $config_ty:ty, _ => $default:expr) => {
+        impl $crate::config::style_edition::StyleEditionDefault for $ty {
+            type ConfigType = $config_ty;
+
+            fn style_edition_default(_: $crate::config::StyleEdition) -> Self::ConfigType {
+                $default
+            }
+        }
+    };
+    ($ty:ident, $config_ty:ty, Edition2024 => $default_2024:expr, _ => $default_2015:expr) => {
+        impl $crate::config::style_edition::StyleEditionDefault for $ty {
+            type ConfigType = $config_ty;
+
+            fn style_edition_default(
+                style_edition: $crate::config::StyleEdition,
+            ) -> Self::ConfigType {
+                match style_edition {
+                    $crate::config::StyleEdition::Edition2015
+                    | $crate::config::StyleEdition::Edition2018
+                    | $crate::config::StyleEdition::Edition2021 => $default_2015,
+                    $crate::config::StyleEdition::Edition2024 => $default_2024,
+                }
+            }
+        }
+    };
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use crate::config::StyleEdition;
+
+    #[test]
+    fn test_impl_default_style_edition_struct_for_all_editions() {
+        struct Unit;
+        style_edition_default!(Unit, usize, _ => 100);
+
+        // regardless of the style edition used the value will always return 100
+        assert_eq!(Unit::style_edition_default(StyleEdition::Edition2015), 100);
+        assert_eq!(Unit::style_edition_default(StyleEdition::Edition2018), 100);
+        assert_eq!(Unit::style_edition_default(StyleEdition::Edition2021), 100);
+        assert_eq!(Unit::style_edition_default(StyleEdition::Edition2024), 100);
+    }
+
+    #[test]
+    fn test_impl_default_style_edition_for_old_and_new_editions() {
+        struct Unit;
+        style_edition_default!(Unit, usize, Edition2024 => 50, _ => 100);
+
+        // style edition 2015-2021 are all the same
+        assert_eq!(Unit::style_edition_default(StyleEdition::Edition2015), 100);
+        assert_eq!(Unit::style_edition_default(StyleEdition::Edition2018), 100);
+        assert_eq!(Unit::style_edition_default(StyleEdition::Edition2021), 100);
+
+        // style edition 2024
+        assert_eq!(Unit::style_edition_default(StyleEdition::Edition2024), 50);
+    }
+}
diff --git a/src/tools/rustfmt/src/emitter/checkstyle.rs b/src/tools/rustfmt/src/emitter/checkstyle.rs
index 2a4a9dfce8e..9385ae59a06 100644
--- a/src/tools/rustfmt/src/emitter/checkstyle.rs
+++ b/src/tools/rustfmt/src/emitter/checkstyle.rs
@@ -89,11 +89,11 @@ mod tests {
     #[test]
     fn emits_single_xml_tree_containing_all_files() {
         let bin_file = "src/bin.rs";
-        let bin_original = vec!["fn main() {", "println!(\"Hello, world!\");", "}"];
-        let bin_formatted = vec!["fn main() {", "    println!(\"Hello, world!\");", "}"];
+        let bin_original = ["fn main() {", "println!(\"Hello, world!\");", "}"];
+        let bin_formatted = ["fn main() {", "    println!(\"Hello, world!\");", "}"];
         let lib_file = "src/lib.rs";
-        let lib_original = vec!["fn greet() {", "println!(\"Greetings!\");", "}"];
-        let lib_formatted = vec!["fn greet() {", "    println!(\"Greetings!\");", "}"];
+        let lib_original = ["fn greet() {", "println!(\"Greetings!\");", "}"];
+        let lib_formatted = ["fn greet() {", "    println!(\"Greetings!\");", "}"];
         let mut writer = Vec::new();
         let mut emitter = CheckstyleEmitter::default();
         let _ = emitter.emit_header(&mut writer);
@@ -118,7 +118,7 @@ mod tests {
             )
             .unwrap();
         let _ = emitter.emit_footer(&mut writer);
-        let exp_bin_xml = vec![
+        let exp_bin_xml = [
             format!(r#"<file name="{}">"#, bin_file),
             format!(
                 r#"<error line="2" severity="warning" message="Should be `{}`" />"#,
@@ -126,7 +126,7 @@ mod tests {
             ),
             String::from("</file>"),
         ];
-        let exp_lib_xml = vec![
+        let exp_lib_xml = [
             format!(r#"<file name="{}">"#, lib_file),
             format!(
                 r#"<error line="2" severity="warning" message="Should be `{}`" />"#,
@@ -136,7 +136,7 @@ mod tests {
         ];
         assert_eq!(
             String::from_utf8(writer).unwrap(),
-            vec![
+            [
                 r#"<?xml version="1.0" encoding="utf-8"?>"#,
                 "\n",
                 r#"<checkstyle version="4.3">"#,
diff --git a/src/tools/rustfmt/src/emitter/diff.rs b/src/tools/rustfmt/src/emitter/diff.rs
index 0af19a7d0b2..4e48c59ea29 100644
--- a/src/tools/rustfmt/src/emitter/diff.rs
+++ b/src/tools/rustfmt/src/emitter/diff.rs
@@ -32,7 +32,7 @@ impl Emitter for DiffEmitter {
             } else {
                 print_diff(
                     mismatch,
-                    |line_num| format!("Diff in {} at line {}:", filename, line_num),
+                    |line_num| format!("Diff in {}:{}:", filename, line_num),
                     &self.config,
                 );
             }
diff --git a/src/tools/rustfmt/src/emitter/json.rs b/src/tools/rustfmt/src/emitter/json.rs
index f47c3260a02..084f565804c 100644
--- a/src/tools/rustfmt/src/emitter/json.rs
+++ b/src/tools/rustfmt/src/emitter/json.rs
@@ -212,7 +212,7 @@ mod tests {
     #[test]
     fn emits_array_with_files_with_diffs() {
         let file_name = "src/bin.rs";
-        let original = vec![
+        let original = [
             "fn main() {",
             "println!(\"Hello, world!\");",
             "}",
@@ -225,7 +225,7 @@ mod tests {
             "}",
             "}",
         ];
-        let formatted = vec![
+        let formatted = [
             "fn main() {",
             "    println!(\"Hello, world!\");",
             "}",
@@ -285,11 +285,11 @@ mod tests {
     #[test]
     fn emits_valid_json_with_multiple_files() {
         let bin_file = "src/bin.rs";
-        let bin_original = vec!["fn main() {", "println!(\"Hello, world!\");", "}"];
-        let bin_formatted = vec!["fn main() {", "    println!(\"Hello, world!\");", "}"];
+        let bin_original = ["fn main() {", "println!(\"Hello, world!\");", "}"];
+        let bin_formatted = ["fn main() {", "    println!(\"Hello, world!\");", "}"];
         let lib_file = "src/lib.rs";
-        let lib_original = vec!["fn greet() {", "println!(\"Greetings!\");", "}"];
-        let lib_formatted = vec!["fn greet() {", "    println!(\"Greetings!\");", "}"];
+        let lib_original = ["fn greet() {", "println!(\"Greetings!\");", "}"];
+        let lib_formatted = ["fn greet() {", "    println!(\"Greetings!\");", "}"];
         let mut writer = Vec::new();
         let mut emitter = JsonEmitter::default();
         let _ = emitter.emit_header(&mut writer);
diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs
index 053afcc52d4..c7c4b680b07 100644
--- a/src/tools/rustfmt/src/expr.rs
+++ b/src/tools/rustfmt/src/expr.rs
@@ -139,7 +139,17 @@ pub(crate) fn format_expr(
         | ast::ExprKind::While(..) => to_control_flow(expr, expr_type)
             .and_then(|control_flow| control_flow.rewrite(context, shape)),
         ast::ExprKind::ConstBlock(ref anon_const) => {
-            Some(format!("const {}", anon_const.rewrite(context, shape)?))
+            let rewrite = match anon_const.value.kind {
+                ast::ExprKind::Block(ref block, opt_label) => {
+                    // Inner attributes are associated with the `ast::ExprKind::ConstBlock` node,
+                    // not the `ast::Block` node we're about to rewrite. To prevent dropping inner
+                    // attributes call `rewrite_block` directly.
+                    // See https://github.com/rust-lang/rustfmt/issues/6158
+                    rewrite_block(block, Some(&expr.attrs), opt_label, context, shape)?
+                }
+                _ => anon_const.rewrite(context, shape)?,
+            };
+            Some(format!("const {}", rewrite))
         }
         ast::ExprKind::Block(ref block, opt_label) => {
             match expr_type {
@@ -253,14 +263,6 @@ pub(crate) fn format_expr(
             shape,
             SeparatorPlace::Front,
         ),
-        ast::ExprKind::Type(ref expr, ref ty) => rewrite_pair(
-            &**expr,
-            &**ty,
-            PairParts::infix(": "),
-            context,
-            shape,
-            SeparatorPlace::Back,
-        ),
         ast::ExprKind::Index(ref expr, ref index, _) => {
             rewrite_index(&**expr, &**index, context, shape)
         }
@@ -282,6 +284,9 @@ pub(crate) fn format_expr(
                 match lhs.kind {
                     ast::ExprKind::Lit(token_lit) => lit_ends_in_dot(&token_lit),
                     ast::ExprKind::Unary(_, ref expr) => needs_space_before_range(context, expr),
+                    ast::ExprKind::Binary(_, _, ref rhs_expr) => {
+                        needs_space_before_range(context, rhs_expr)
+                    }
                     _ => false,
                 }
             }
@@ -367,7 +372,7 @@ pub(crate) fn format_expr(
                 ))
             }
         }
-        ast::ExprKind::Gen(capture_by, ref block, ref kind) => {
+        ast::ExprKind::Gen(capture_by, ref block, ref kind, _) => {
             let mover = if matches!(capture_by, ast::CaptureBy::Value { .. }) {
                 "move "
             } else {
@@ -399,10 +404,14 @@ pub(crate) fn format_expr(
         }
         ast::ExprKind::Underscore => Some("_".to_owned()),
         ast::ExprKind::FormatArgs(..)
+        | ast::ExprKind::Type(..)
         | ast::ExprKind::IncludedBytes(..)
         | ast::ExprKind::OffsetOf(..) => {
-            // These do not occur in the AST because macros aren't expanded.
-            unreachable!()
+            // These don't normally occur in the AST because macros aren't expanded. However,
+            // rustfmt tries to parse macro arguments when formatting macros, so it's not totally
+            // impossible for rustfmt to come across one of these nodes when formatting a file.
+            // Also, rustfmt might get passed the output from `-Zunpretty=expanded`.
+            None
         }
         ast::ExprKind::Err(_) | ast::ExprKind::Dummy => None,
     };
diff --git a/src/tools/rustfmt/src/format-diff/main.rs b/src/tools/rustfmt/src/format-diff/main.rs
index 61e2cb711a5..f9eb70f6e04 100644
--- a/src/tools/rustfmt/src/format-diff/main.rs
+++ b/src/tools/rustfmt/src/format-diff/main.rs
@@ -38,14 +38,14 @@ enum FormatDiffError {
 }
 
 #[derive(Parser, Debug)]
-#[clap(
+#[command(
     name = "rustfmt-format-diff",
     disable_version_flag = true,
     next_line_help = true
 )]
 pub struct Opts {
     /// Skip the smallest prefix containing NUMBER slashes
-    #[clap(
+    #[arg(
         short = 'p',
         long = "skip-prefix",
         value_name = "NUMBER",
@@ -54,7 +54,7 @@ pub struct Opts {
     skip_prefix: u32,
 
     /// Custom pattern selecting file paths to reformat
-    #[clap(
+    #[arg(
         short = 'f',
         long = "filter",
         value_name = "PATTERN",
@@ -234,14 +234,14 @@ mod cmd_line_tests {
     #[test]
     fn default_options() {
         let empty: Vec<String> = vec![];
-        let o = Opts::parse_from(&empty);
+        let o = Opts::parse_from(empty);
         assert_eq!(DEFAULT_PATTERN, o.filter);
         assert_eq!(0, o.skip_prefix);
     }
 
     #[test]
     fn good_options() {
-        let o = Opts::parse_from(&["test", "-p", "10", "-f", r".*\.hs"]);
+        let o = Opts::parse_from(["test", "-p", "10", "-f", r".*\.hs"]);
         assert_eq!(r".*\.hs", o.filter);
         assert_eq!(10, o.skip_prefix);
     }
@@ -250,7 +250,7 @@ mod cmd_line_tests {
     fn unexpected_option() {
         assert!(
             Opts::command()
-                .try_get_matches_from(&["test", "unexpected"])
+                .try_get_matches_from(["test", "unexpected"])
                 .is_err()
         );
     }
@@ -259,7 +259,7 @@ mod cmd_line_tests {
     fn unexpected_flag() {
         assert!(
             Opts::command()
-                .try_get_matches_from(&["test", "--flag"])
+                .try_get_matches_from(["test", "--flag"])
                 .is_err()
         );
     }
@@ -268,7 +268,7 @@ mod cmd_line_tests {
     fn overridden_option() {
         assert!(
             Opts::command()
-                .try_get_matches_from(&["test", "-p", "10", "-p", "20"])
+                .try_get_matches_from(["test", "-p", "10", "-p", "20"])
                 .is_err()
         );
     }
@@ -277,7 +277,7 @@ mod cmd_line_tests {
     fn negative_filter() {
         assert!(
             Opts::command()
-                .try_get_matches_from(&["test", "-p", "-1"])
+                .try_get_matches_from(["test", "-p", "-1"])
                 .is_err()
         );
     }
diff --git a/src/tools/rustfmt/src/formatting.rs b/src/tools/rustfmt/src/formatting.rs
index 3bcb4d15184..7f442230b12 100644
--- a/src/tools/rustfmt/src/formatting.rs
+++ b/src/tools/rustfmt/src/formatting.rs
@@ -82,7 +82,7 @@ fn should_skip_module<T: FormatHandler>(
         let source_file = context.psess.span_to_file_contents(module.span);
         let src = source_file.src.as_ref().expect("SourceFile without src");
 
-        if is_generated_file(src) {
+        if is_generated_file(src, config) {
             return true;
         }
     }
diff --git a/src/tools/rustfmt/src/formatting/generated.rs b/src/tools/rustfmt/src/formatting/generated.rs
index 58f43f17ee1..68ffee6e664 100644
--- a/src/tools/rustfmt/src/formatting/generated.rs
+++ b/src/tools/rustfmt/src/formatting/generated.rs
@@ -1,7 +1,10 @@
+use crate::Config;
+
 /// Returns `true` if the given span is a part of generated files.
-pub(super) fn is_generated_file(original_snippet: &str) -> bool {
+pub(super) fn is_generated_file(original_snippet: &str, config: &Config) -> bool {
     original_snippet
         .lines()
-        .take(5) // looking for marker only in the beginning of the file
+        // looking for marker only in the beginning of the file
+        .take(config.generated_marker_line_search_limit())
         .any(|line| line.contains("@generated"))
 }
diff --git a/src/tools/rustfmt/src/ignore_path.rs b/src/tools/rustfmt/src/ignore_path.rs
index 7b5697bec3e..5c25f233ce3 100644
--- a/src/tools/rustfmt/src/ignore_path.rs
+++ b/src/tools/rustfmt/src/ignore_path.rs
@@ -49,4 +49,22 @@ mod test {
         assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("bar_dir/baz.rs"))));
         assert!(!ignore_path_set.is_match(&FileName::Real(PathBuf::from("src/bar.rs"))));
     }
+
+    #[nightly_only_test]
+    #[test]
+    fn test_negated_ignore_path_set() {
+        use crate::config::{Config, FileName};
+        use crate::ignore_path::IgnorePathSet;
+        use std::path::{Path, PathBuf};
+
+        let config = Config::from_toml(
+            r#"ignore = ["foo.rs", "bar_dir/*", "!bar_dir/*/what.rs"]"#,
+            Path::new(""),
+        )
+        .unwrap();
+        let ignore_path_set = IgnorePathSet::from_ignore_list(&config.ignore()).unwrap();
+        assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("bar_dir/what.rs"))));
+        assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("bar_dir/baz/a.rs"))));
+        assert!(!ignore_path_set.is_match(&FileName::Real(PathBuf::from("bar_dir/baz/what.rs"))));
+    }
 }
diff --git a/src/tools/rustfmt/src/imports.rs b/src/tools/rustfmt/src/imports.rs
index 2da746295fc..12c178e136f 100644
--- a/src/tools/rustfmt/src/imports.rs
+++ b/src/tools/rustfmt/src/imports.rs
@@ -685,9 +685,9 @@ impl UseTree {
                 let prefix = &self.path[..self.path.len() - 1];
                 let mut result = vec![];
                 for nested_use_tree in list {
-                    for flattend in &mut nested_use_tree.clone().flatten(import_granularity) {
+                    for flattened in &mut nested_use_tree.clone().flatten(import_granularity) {
                         let mut new_path = prefix.to_vec();
-                        new_path.append(&mut flattend.path);
+                        new_path.append(&mut flattened.path);
                         result.push(UseTree {
                             path: new_path,
                             span: self.span,
diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs
index e869787b394..eb11604b277 100644
--- a/src/tools/rustfmt/src/items.rs
+++ b/src/tools/rustfmt/src/items.rs
@@ -656,9 +656,16 @@ impl<'a> FmtVisitor<'a> {
         }
 
         let context = self.get_context();
-        // 1 = ','
-        let shape = self.shape().sub_width(1)?;
-        let attrs_str = field.attrs.rewrite(&context, shape)?;
+        let shape = self.shape();
+        let attrs_str = if context.config.version() == Version::Two {
+            field.attrs.rewrite(&context, shape)?
+        } else {
+            // Version::One formatting that was off by 1. See issue #5801
+            field.attrs.rewrite(&context, shape.sub_width(1)?)?
+        };
+        // sub_width(1) to take the trailing comma into account
+        let shape = shape.sub_width(1)?;
+
         let lo = field
             .attrs
             .last()
@@ -836,13 +843,15 @@ pub(crate) fn format_impl(
 
     if is_impl_single_line(context, items.as_slice(), &result, &where_clause_str, item)? {
         result.push_str(&where_clause_str);
-        if where_clause_str.contains('\n') || last_line_contains_single_line_comment(&result) {
-            // if the where_clause contains extra comments AND
-            // there is only one where-clause predicate
-            // recover the suppressed comma in single line where_clause formatting
+        if where_clause_str.contains('\n') {
+            // If there is only one where-clause predicate
+            // and the where-clause spans multiple lines,
+            // then recover the suppressed comma in single line where-clause formatting
             if generics.where_clause.predicates.len() == 1 {
                 result.push(',');
             }
+        }
+        if where_clause_str.contains('\n') || last_line_contains_single_line_comment(&result) {
             result.push_str(&format!("{sep}{{{sep}}}"));
         } else {
             result.push_str(" {}");
@@ -1161,9 +1170,9 @@ pub(crate) fn format_trait(
 
     // FIXME(#2055): rustfmt fails to format when there are comments between trait bounds.
     if !bounds.is_empty() {
-        let ident_hi = context
-            .snippet_provider
-            .span_after(item.span, item.ident.as_str());
+        // Retrieve *unnormalized* ident (See #6069)
+        let source_ident = context.snippet(item.ident.span);
+        let ident_hi = context.snippet_provider.span_after(item.span, source_ident);
         let bound_hi = bounds.last().unwrap().span().hi();
         let snippet = context.snippet(mk_sp(ident_hi, bound_hi));
         if contains_comment(snippet) {
@@ -1906,6 +1915,7 @@ pub(crate) fn rewrite_struct_field(
 
 pub(crate) struct StaticParts<'a> {
     prefix: &'a str,
+    safety: ast::Safety,
     vis: &'a ast::Visibility,
     ident: symbol::Ident,
     ty: &'a ast::Ty,
@@ -1917,11 +1927,12 @@ pub(crate) struct StaticParts<'a> {
 
 impl<'a> StaticParts<'a> {
     pub(crate) fn from_item(item: &'a ast::Item) -> Self {
-        let (defaultness, prefix, ty, mutability, expr) = match &item.kind {
-            ast::ItemKind::Static(s) => (None, "static", &s.ty, s.mutability, &s.expr),
+        let (defaultness, prefix, safety, ty, mutability, expr) = match &item.kind {
+            ast::ItemKind::Static(s) => (None, "static", s.safety, &s.ty, s.mutability, &s.expr),
             ast::ItemKind::Const(c) => (
                 Some(c.defaultness),
                 "const",
+                ast::Safety::Default,
                 &c.ty,
                 ast::Mutability::Not,
                 &c.expr,
@@ -1930,6 +1941,7 @@ impl<'a> StaticParts<'a> {
         };
         StaticParts {
             prefix,
+            safety,
             vis: &item.vis,
             ident: item.ident,
             ty,
@@ -1947,6 +1959,7 @@ impl<'a> StaticParts<'a> {
         };
         StaticParts {
             prefix: "const",
+            safety: ast::Safety::Default,
             vis: &ti.vis,
             ident: ti.ident,
             ty,
@@ -1964,6 +1977,7 @@ impl<'a> StaticParts<'a> {
         };
         StaticParts {
             prefix: "const",
+            safety: ast::Safety::Default,
             vis: &ii.vis,
             ident: ii.ident,
             ty,
@@ -1982,9 +1996,10 @@ fn rewrite_static(
 ) -> Option<String> {
     let colon = colon_spaces(context.config);
     let mut prefix = format!(
-        "{}{}{} {}{}{}",
+        "{}{}{}{} {}{}{}",
         format_visibility(context, static_parts.vis),
         static_parts.defaultness.map_or("", format_defaultness),
+        format_safety(static_parts.safety),
         static_parts.prefix,
         format_mutability(static_parts.mutability),
         rewrite_ident(context, static_parts.ident),
@@ -2483,7 +2498,7 @@ fn rewrite_fn_base(
                 || context.config.indent_style() == IndentStyle::Visual
             {
                 let indent = if param_str.is_empty() {
-                    // Aligning with non-existent params looks silly.
+                    // Aligning with nonexistent params looks silly.
                     force_new_line_for_brace = true;
                     indent + 4
                 } else {
@@ -2498,7 +2513,7 @@ fn rewrite_fn_base(
             } else {
                 let mut ret_shape = Shape::indented(indent, context.config);
                 if param_str.is_empty() {
-                    // Aligning with non-existent params looks silly.
+                    // Aligning with nonexistent params looks silly.
                     force_new_line_for_brace = true;
                     ret_shape = if context.use_block_indent() {
                         ret_shape.offset_left(4).unwrap_or(ret_shape)
@@ -3329,10 +3344,12 @@ impl Rewrite for ast::ForeignItem {
                 // FIXME(#21): we're dropping potential comments in between the
                 // function kw here.
                 let vis = format_visibility(context, &self.vis);
+                let safety = format_safety(static_foreign_item.safety);
                 let mut_str = format_mutability(static_foreign_item.mutability);
                 let prefix = format!(
-                    "{}static {}{}:",
+                    "{}{}static {}{}:",
                     vis,
+                    safety,
                     mut_str,
                     rewrite_ident(context, self.ident)
                 );
diff --git a/src/tools/rustfmt/src/lib.rs b/src/tools/rustfmt/src/lib.rs
index 877d057a34b..ff2b14af078 100644
--- a/src/tools/rustfmt/src/lib.rs
+++ b/src/tools/rustfmt/src/lib.rs
@@ -5,9 +5,6 @@
 #![allow(clippy::match_like_matches_macro)]
 #![allow(unreachable_pub)]
 
-#[cfg(test)]
-#[macro_use]
-extern crate lazy_static;
 #[macro_use]
 extern crate tracing;
 
@@ -62,6 +59,13 @@ pub use crate::rustfmt_diff::{ModifiedChunk, ModifiedLines};
 #[macro_use]
 mod utils;
 
+macro_rules! static_regex {
+    ($re:literal) => {{
+        static RE: ::std::sync::OnceLock<::regex::Regex> = ::std::sync::OnceLock::new();
+        RE.get_or_init(|| ::regex::Regex::new($re).unwrap())
+    }};
+}
+
 mod attr;
 mod chains;
 mod closures;
@@ -258,8 +262,8 @@ impl FormatReport {
         self.internal
             .borrow()
             .0
-            .iter()
-            .map(|(_, errors)| errors.len())
+            .values()
+            .map(|errors| errors.len())
             .sum()
     }
 
@@ -305,7 +309,7 @@ fn format_snippet(snippet: &str, config: &Config, is_macro_def: bool) -> Option<
         let mut out: Vec<u8> = Vec::with_capacity(snippet.len() * 2);
         config.set().emit_mode(config::EmitMode::Stdout);
         config.set().verbose(Verbosity::Quiet);
-        config.set().hide_parse_errors(true);
+        config.set().show_parse_errors(false);
         if is_macro_def {
             config.set().error_on_unformatted(true);
         }
diff --git a/src/tools/rustfmt/src/macros.rs b/src/tools/rustfmt/src/macros.rs
index 6b24b1aec5d..a0582b061c0 100644
--- a/src/tools/rustfmt/src/macros.rs
+++ b/src/tools/rustfmt/src/macros.rs
@@ -25,6 +25,7 @@ use crate::comment::{
     contains_comment, CharClasses, FindUncommented, FullCodeCharKind, LineClasses,
 };
 use crate::config::lists::*;
+use crate::config::Version;
 use crate::expr::{rewrite_array, rewrite_assign_rhs, RhsAssignKind};
 use crate::lists::{itemize_list, write_list, ListFormatting};
 use crate::overflow;
@@ -389,7 +390,7 @@ fn rewrite_empty_macro_def_body(
         stmts: vec![].into(),
         id: rustc_ast::node_id::DUMMY_NODE_ID,
         rules: ast::BlockCheckMode::Default,
-        span: span,
+        span,
         tokens: None,
         could_be_bare_literal: false,
     };
@@ -1245,8 +1246,16 @@ impl MacroBranch {
             return None;
         }
 
-        // 5 = " => {"
-        let mut result = format_macro_args(context, self.args.clone(), shape.sub_width(5)?)?;
+        let old_body = context.snippet(self.body).trim();
+        let has_block_body = old_body.starts_with('{');
+        let mut prefix_width = 5; // 5 = " => {"
+        if context.config.version() == Version::Two {
+            if has_block_body {
+                prefix_width = 6; // 6 = " => {{"
+            }
+        }
+        let mut result =
+            format_macro_args(context, self.args.clone(), shape.sub_width(prefix_width)?)?;
 
         if multi_branch_style {
             result += " =>";
@@ -1264,12 +1273,10 @@ impl MacroBranch {
         // `$$`). We'll try and format like an AST node, but we'll substitute
         // variables for new names with the same length first.
 
-        let old_body = context.snippet(self.body).trim();
         let (body_str, substs) = replace_names(old_body)?;
-        let has_block_body = old_body.starts_with('{');
 
         let mut config = context.config.clone();
-        config.set().hide_parse_errors(true);
+        config.set().show_parse_errors(false);
 
         result += " {";
 
diff --git a/src/tools/rustfmt/src/matches.rs b/src/tools/rustfmt/src/matches.rs
index e68903c8715..e4fa077073c 100644
--- a/src/tools/rustfmt/src/matches.rs
+++ b/src/tools/rustfmt/src/matches.rs
@@ -5,7 +5,7 @@ use std::iter::repeat;
 use rustc_ast::{ast, ptr, MatchKind};
 use rustc_span::{BytePos, Span};
 
-use crate::comment::{combine_strs_with_missing_comments, rewrite_comment};
+use crate::comment::{combine_strs_with_missing_comments, rewrite_comment, FindUncommented};
 use crate::config::lists::*;
 use crate::config::{Config, ControlBraceStyle, IndentStyle, MatchArmLeadingPipe, Version};
 use crate::expr::{
@@ -104,6 +104,10 @@ pub(crate) fn rewrite_match(
     let inner_attrs_str = if inner_attrs.is_empty() {
         String::new()
     } else {
+        let shape = match context.config.version() {
+            Version::One => shape,
+            _ => shape.block_indent(context.config.tab_spaces()),
+        };
         inner_attrs
             .rewrite(context, shape)
             .map(|s| format!("{}{}\n", nested_indent_str, s))?
@@ -352,10 +356,10 @@ fn flatten_arm_body<'a>(
                     (true, body)
                 }
             } else {
-                let cond_becomes_muti_line = opt_shape
+                let cond_becomes_multi_line = opt_shape
                     .and_then(|shape| rewrite_cond(context, expr, shape))
                     .map_or(false, |cond| cond.contains('\n'));
-                if cond_becomes_muti_line {
+                if cond_becomes_multi_line {
                     (false, &*body)
                 } else {
                     (can_extend(expr), &*expr)
@@ -415,7 +419,11 @@ fn rewrite_match_body(
         let arrow_snippet = context.snippet(arrow_span).trim();
         // search for the arrow starting from the end of the snippet since there may be a match
         // expression within the guard
-        let arrow_index = arrow_snippet.rfind("=>").unwrap();
+        let arrow_index = if context.config.version() == Version::One {
+            arrow_snippet.rfind("=>").unwrap()
+        } else {
+            arrow_snippet.find_last_uncommented("=>").unwrap()
+        };
         // 2 = `=>`
         let comment_str = arrow_snippet[arrow_index + 2..].trim();
         if comment_str.is_empty() {
@@ -464,8 +472,8 @@ fn rewrite_match_body(
             };
 
         let block_sep = match context.config.control_brace_style() {
-            ControlBraceStyle::AlwaysNextLine => format!("{}{}", alt_block_sep, body_prefix),
             _ if body_prefix.is_empty() => "".to_owned(),
+            ControlBraceStyle::AlwaysNextLine => format!("{}{}", alt_block_sep, body_prefix),
             _ if forbid_same_line || !arrow_comment.is_empty() => {
                 format!("{}{}", alt_block_sep, body_prefix)
             }
diff --git a/src/tools/rustfmt/src/overflow.rs b/src/tools/rustfmt/src/overflow.rs
index f46583b1c89..a1de71a35be 100644
--- a/src/tools/rustfmt/src/overflow.rs
+++ b/src/tools/rustfmt/src/overflow.rs
@@ -8,8 +8,8 @@ use rustc_ast::{ast, ptr};
 use rustc_span::Span;
 
 use crate::closures;
-use crate::config::lists::*;
 use crate::config::Version;
+use crate::config::{lists::*, Config};
 use crate::expr::{
     can_be_overflowed_expr, is_every_expr_simple, is_method_call, is_nested_call, is_simple_expr,
     rewrite_cond,
@@ -60,6 +60,13 @@ const SPECIAL_CASE_MACROS: &[(&str, usize)] = &[
     ("debug_assert_ne!", 2),
 ];
 
+/// Additional special case macros for version 2; these are separated to avoid breaking changes in
+/// version 1.
+const SPECIAL_CASE_MACROS_V2: &[(&str, usize)] = &[
+    // From the `log` crate.
+    ("trace!", 0),
+];
+
 const SPECIAL_CASE_ATTR: &[(&str, usize)] = &[
     // From the `failure` crate.
     ("fail", 0),
@@ -76,6 +83,7 @@ pub(crate) enum OverflowableItem<'a> {
     TuplePatField(&'a TuplePatField<'a>),
     Ty(&'a ast::Ty),
     Pat(&'a ast::Pat),
+    PreciseCapturingArg(&'a ast::PreciseCapturingArg),
 }
 
 impl<'a> Rewrite for OverflowableItem<'a> {
@@ -116,6 +124,7 @@ impl<'a> OverflowableItem<'a> {
             OverflowableItem::TuplePatField(pat) => f(*pat),
             OverflowableItem::Ty(ty) => f(*ty),
             OverflowableItem::Pat(pat) => f(*pat),
+            OverflowableItem::PreciseCapturingArg(arg) => f(*arg),
         }
     }
 
@@ -130,6 +139,9 @@ impl<'a> OverflowableItem<'a> {
                     matches!(meta_item.kind, ast::MetaItemKind::Word)
                 }
             },
+            // FIXME: Why don't we consider `SegmentParam` to be simple?
+            // FIXME: If we also fix `SegmentParam`, then we should apply the same
+            // heuristic to `PreciseCapturingArg`.
             _ => false,
         }
     }
@@ -182,12 +194,17 @@ impl<'a> OverflowableItem<'a> {
         }
     }
 
-    fn special_cases(&self) -> &'static [(&'static str, usize)] {
-        match self {
+    fn special_cases(&self, config: &Config) -> impl Iterator<Item = &(&'static str, usize)> {
+        let base_cases = match self {
             OverflowableItem::MacroArg(..) => SPECIAL_CASE_MACROS,
             OverflowableItem::NestedMetaItem(..) => SPECIAL_CASE_ATTR,
             _ => &[],
-        }
+        };
+        let additional_cases = match (self, config.version()) {
+            (OverflowableItem::MacroArg(..), Version::Two) => SPECIAL_CASE_MACROS_V2,
+            _ => &[],
+        };
+        base_cases.iter().chain(additional_cases)
     }
 }
 
@@ -232,7 +249,15 @@ macro_rules! impl_into_overflowable_item_for_rustfmt_types {
     }
 }
 
-impl_into_overflowable_item_for_ast_node!(Expr, GenericParam, NestedMetaItem, FieldDef, Ty, Pat);
+impl_into_overflowable_item_for_ast_node!(
+    Expr,
+    GenericParam,
+    NestedMetaItem,
+    FieldDef,
+    Ty,
+    Pat,
+    PreciseCapturingArg
+);
 impl_into_overflowable_item_for_rustfmt_types!([MacroArg], [SegmentParam, TuplePatField]);
 
 pub(crate) fn into_overflowable_list<'a, T>(
@@ -511,7 +536,7 @@ impl<'a> Context<'a> {
                 // However, when the inner function has a prefix or a suffix
                 // (e.g., `foo() as u32`), this budget reduction may produce poorly
                 // formatted code, where a prefix or a suffix being left on its own
-                // line. Here we explicitlly check those cases.
+                // line. Here we explicitly check those cases.
                 if count_newlines(overflowed) == 1 {
                     let rw = self
                         .items
@@ -551,7 +576,7 @@ impl<'a> Context<'a> {
 
                     if tactic == DefinitiveListTactic::Vertical {
                         if let Some((all_simple, num_args_before)) =
-                            maybe_get_args_offset(self.ident, &self.items)
+                            maybe_get_args_offset(self.ident, &self.items, &self.context.config)
                         {
                             let one_line = all_simple
                                 && definitive_tactic(
@@ -771,11 +796,11 @@ fn no_long_items(list: &[ListItem], short_array_element_width_threshold: usize)
 pub(crate) fn maybe_get_args_offset(
     callee_str: &str,
     args: &[OverflowableItem<'_>],
+    config: &Config,
 ) -> Option<(bool, usize)> {
     if let Some(&(_, num_args_before)) = args
         .get(0)?
-        .special_cases()
-        .iter()
+        .special_cases(config)
         .find(|&&(s, _)| s == callee_str)
     {
         let all_simple = args.len() > num_args_before
diff --git a/src/tools/rustfmt/src/parse/macros/lazy_static.rs b/src/tools/rustfmt/src/parse/macros/lazy_static.rs
index 7026935294a..7baac247e22 100644
--- a/src/tools/rustfmt/src/parse/macros/lazy_static.rs
+++ b/src/tools/rustfmt/src/parse/macros/lazy_static.rs
@@ -31,7 +31,6 @@ pub(crate) fn parse_lazy_static(
             }
         }
     }
-
     while parser.token.kind != TokenKind::Eof {
         // Parse a `lazy_static!` item.
         let vis = parse_or!(parse_visibility, rustc_parse::parser::FollowedByType::No);
diff --git a/src/tools/rustfmt/src/parse/macros/mod.rs b/src/tools/rustfmt/src/parse/macros/mod.rs
index 89169e10715..60c827fd03b 100644
--- a/src/tools/rustfmt/src/parse/macros/mod.rs
+++ b/src/tools/rustfmt/src/parse/macros/mod.rs
@@ -1,4 +1,4 @@
-use rustc_ast::token::{Delimiter, NonterminalKind, TokenKind};
+use rustc_ast::token::{Delimiter, NonterminalKind, NtExprKind::*, NtPatKind::*, TokenKind};
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::{ast, ptr};
 use rustc_parse::parser::{ForceCollect, Parser, Recovery};
@@ -48,7 +48,7 @@ fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> {
 
     parse_macro_arg!(
         Expr,
-        NonterminalKind::Expr,
+        NonterminalKind::Expr(Expr),
         |parser: &mut Parser<'b>| parser.parse_expr(),
         |x: ptr::P<ast::Expr>| Some(x)
     );
@@ -60,7 +60,7 @@ fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> {
     );
     parse_macro_arg!(
         Pat,
-        NonterminalKind::PatParam { inferred: false },
+        NonterminalKind::Pat(PatParam { inferred: false }),
         |parser: &mut Parser<'b>| parser.parse_pat_no_top_alt(None, None),
         |x: ptr::P<ast::Pat>| Some(x)
     );
diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs
index f4fbabaf6c9..05cf467167c 100644
--- a/src/tools/rustfmt/src/parse/session.rs
+++ b/src/tools/rustfmt/src/parse/session.rs
@@ -97,7 +97,7 @@ fn default_dcx(
     source_map: Lrc<SourceMap>,
     ignore_path_set: Lrc<IgnorePathSet>,
     can_reset: Lrc<AtomicBool>,
-    hide_parse_errors: bool,
+    show_parse_errors: bool,
     color: Color,
 ) -> DiagCtxt {
     let supports_color = term::stderr().map_or(false, |term| term.supports_color());
@@ -116,7 +116,7 @@ fn default_dcx(
             .sm(Some(source_map.clone())),
     );
 
-    let emitter: Box<DynEmitter> = if hide_parse_errors {
+    let emitter: Box<DynEmitter> = if !show_parse_errors {
         Box::new(SilentEmitter {
             fallback_bundle,
             fatal_dcx: DiagCtxt::new(emitter),
@@ -148,7 +148,7 @@ impl ParseSess {
             Lrc::clone(&source_map),
             Lrc::clone(&ignore_path_set),
             Lrc::clone(&can_reset_errors),
-            config.hide_parse_errors(),
+            config.show_parse_errors(),
             config.color(),
         );
         let raw_psess = RawParseSess::with_dcx(dcx, source_map);
@@ -164,7 +164,7 @@ impl ParseSess {
     ///
     /// * `id` - The name of the module
     /// * `relative` - If Some(symbol), the symbol name is a directory relative to the dir_path.
-    ///   If relative is Some, resolve the submodle at {dir_path}/{symbol}/{id}.rs
+    ///   If relative is Some, resolve the submodule at {dir_path}/{symbol}/{id}.rs
     ///   or {dir_path}/{symbol}/{id}/mod.rs. if None, resolve the module at {dir_path}/{id}.rs.
     /// *  `dir_path` - Module resolution will occur relative to this directory.
     pub(crate) fn default_submod_path(
@@ -175,7 +175,7 @@ impl ParseSess {
     ) -> Result<ModulePathSuccess, ModError<'_>> {
         rustc_expand::module::default_submod_path(&self.raw_psess, id, relative, dir_path).or_else(
             |e| {
-                // If resloving a module relative to {dir_path}/{symbol} fails because a file
+                // If resolving a module relative to {dir_path}/{symbol} fails because a file
                 // could not be found, then try to resolve the module relative to {dir_path}.
                 // If we still can't find the module after searching for it in {dir_path},
                 // surface the original error.
diff --git a/src/tools/rustfmt/src/source_file.rs b/src/tools/rustfmt/src/source_file.rs
index 2b43ec94b6b..5eea8021b32 100644
--- a/src/tools/rustfmt/src/source_file.rs
+++ b/src/tools/rustfmt/src/source_file.rs
@@ -33,7 +33,7 @@ where
     let mut emitter = create_emitter(config);
 
     emitter.emit_header(out)?;
-    for &(ref filename, ref text) in source_file {
+    for (filename, text) in source_file {
         write_file(
             None,
             filename,
diff --git a/src/tools/rustfmt/src/spanned.rs b/src/tools/rustfmt/src/spanned.rs
index 28911f8af1d..1ee691b4ade 100644
--- a/src/tools/rustfmt/src/spanned.rs
+++ b/src/tools/rustfmt/src/spanned.rs
@@ -203,3 +203,12 @@ impl Spanned for ast::NestedMetaItem {
         self.span()
     }
 }
+
+impl Spanned for ast::PreciseCapturingArg {
+    fn span(&self) -> Span {
+        match self {
+            ast::PreciseCapturingArg::Lifetime(lt) => lt.ident.span,
+            ast::PreciseCapturingArg::Arg(path, _) => path.span,
+        }
+    }
+}
diff --git a/src/tools/rustfmt/src/test/configuration_snippet.rs b/src/tools/rustfmt/src/test/configuration_snippet.rs
index 80b61c88a00..e4a390ada66 100644
--- a/src/tools/rustfmt/src/test/configuration_snippet.rs
+++ b/src/tools/rustfmt/src/test/configuration_snippet.rs
@@ -24,19 +24,13 @@ impl ConfigurationSection {
     fn get_section<I: Iterator<Item = String>>(
         file: &mut Enumerate<I>,
     ) -> Option<ConfigurationSection> {
-        lazy_static! {
-            static ref CONFIG_NAME_REGEX: regex::Regex =
-                regex::Regex::new(r"^## `([^`]+)`").expect("failed creating configuration pattern");
-            // Configuration values, which will be passed to `from_str`:
-            //
-            // - must be prefixed with `####`
-            // - must be wrapped in backticks
-            // - may by wrapped in double quotes (which will be stripped)
-            static ref CONFIG_VALUE_REGEX: regex::Regex =
-                regex::Regex::new(r#"^#### `"?([^`]+?)"?`"#)
-                    .expect("failed creating configuration value pattern");
-        }
-
+        let config_name_regex = static_regex!(r"^## `([^`]+)`");
+        // Configuration values, which will be passed to `from_str`:
+        //
+        // - must be prefixed with `####`
+        // - must be wrapped in backticks
+        // - may by wrapped in double quotes (which will be stripped)
+        let config_value_regex = static_regex!(r#"^#### `"?([^`]+?)"?`"#);
         loop {
             match file.next() {
                 Some((i, line)) => {
@@ -53,9 +47,9 @@ impl ConfigurationSection {
                         let start_line = (i + 2) as u32;
 
                         return Some(ConfigurationSection::CodeBlock((block, start_line)));
-                    } else if let Some(c) = CONFIG_NAME_REGEX.captures(&line) {
+                    } else if let Some(c) = config_name_regex.captures(&line) {
                         return Some(ConfigurationSection::ConfigName(String::from(&c[1])));
-                    } else if let Some(c) = CONFIG_VALUE_REGEX.captures(&line) {
+                    } else if let Some(c) = config_value_regex.captures(&line) {
                         return Some(ConfigurationSection::ConfigValue(String::from(&c[1])));
                     }
                 }
@@ -208,7 +202,7 @@ impl ConfigCodeBlock {
     }
 
     // Extract a code block from the iterator. Behavior:
-    // - Rust code blocks are identifed by lines beginning with "```rust".
+    // - Rust code blocks are identified by lines beginning with "```rust".
     // - One explicit configuration setting is supported per code block.
     // - Rust code blocks with no configuration setting are illegal and cause an
     //   assertion failure, unless the snippet begins with #![rustfmt::skip].
diff --git a/src/tools/rustfmt/src/test/mod.rs b/src/tools/rustfmt/src/test/mod.rs
index 47f89c1871a..7c563801c32 100644
--- a/src/tools/rustfmt/src/test/mod.rs
+++ b/src/tools/rustfmt/src/test/mod.rs
@@ -332,7 +332,7 @@ fn assert_stdin_output(
         let mut session = Session::new(config, Some(&mut buf));
         session.format(input).unwrap();
         let errors = ReportedErrors {
-            has_diff: has_diff,
+            has_diff,
             ..Default::default()
         };
         assert_eq!(session.errors, errors);
@@ -390,6 +390,26 @@ fn self_tests() {
         path.push("main.rs");
         files.push(path);
     }
+    // for crates that need to be included but lies outside src
+    let external_crates = vec!["check_diff", "config_proc_macro"];
+    for external_crate in external_crates {
+        let mut path = PathBuf::from(external_crate);
+        path.push("src");
+        let directory = fs::read_dir(&path).unwrap();
+        let search_files = directory.filter_map(|file| {
+            file.ok().and_then(|f| {
+                let name = f.file_name();
+                if matches!(name.as_os_str().to_str(), Some("main.rs" | "lib.rs")) {
+                    Some(f.path())
+                } else {
+                    None
+                }
+            })
+        });
+        for file in search_files {
+            files.push(file);
+        }
+    }
     files.push(PathBuf::from("src/lib.rs"));
 
     let (reports, count, fails) = check_files(files, &Some(PathBuf::from("rustfmt.toml")));
@@ -835,7 +855,7 @@ fn handle_result(
         // Ignore LF and CRLF difference for Windows.
         if !string_eq_ignore_newline_repr(&fmt_text, &text) {
             if std::env::var_os("RUSTC_BLESS").is_some_and(|v| v != "0") {
-                std::fs::write(file_name, fmt_text).unwrap();
+                std::fs::write(target, fmt_text).unwrap();
                 continue;
             }
             let diff = make_diff(&text, &fmt_text, DIFF_CONTEXT_SIZE);
diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs
index c2c192738c9..c826547e9d0 100644
--- a/src/tools/rustfmt/src/types.rs
+++ b/src/tools/rustfmt/src/types.rs
@@ -43,11 +43,13 @@ pub(crate) fn rewrite_path(
 ) -> Option<String> {
     let skip_count = qself.as_ref().map_or(0, |x| x.position);
 
-    let mut result = if path.is_global() && qself.is_none() && path_context != PathContext::Import {
-        "::".to_owned()
-    } else {
-        String::new()
-    };
+    // 32 covers almost all path lengths measured when compiling core, and there isn't a big
+    // downside from allocating slightly more than necessary.
+    let mut result = String::with_capacity(32);
+
+    if path.is_global() && qself.is_none() && path_context != PathContext::Import {
+        result.push_str("::");
+    }
 
     let mut span_lo = path.span.lo();
 
@@ -175,6 +177,17 @@ impl<'a> Rewrite for SegmentParam<'a> {
     }
 }
 
+impl Rewrite for ast::PreciseCapturingArg {
+    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
+        match self {
+            ast::PreciseCapturingArg::Lifetime(lt) => lt.rewrite(context, shape),
+            ast::PreciseCapturingArg::Arg(p, _) => {
+                rewrite_path(context, PathContext::Type, &None, p, shape)
+            }
+        }
+    }
+}
+
 impl Rewrite for ast::AssocItemConstraint {
     fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
         use ast::AssocItemConstraintKind::{Bound, Equality};
@@ -471,21 +484,25 @@ fn rewrite_generic_args(
     span: Span,
 ) -> Option<String> {
     match gen_args {
-        ast::GenericArgs::AngleBracketed(ref data) if !data.args.is_empty() => {
-            let args = data
-                .args
-                .iter()
-                .map(|x| match x {
-                    ast::AngleBracketedArg::Arg(generic_arg) => {
-                        SegmentParam::from_generic_arg(generic_arg)
-                    }
-                    ast::AngleBracketedArg::Constraint(constraint) => {
-                        SegmentParam::Binding(constraint)
-                    }
-                })
-                .collect::<Vec<_>>();
+        ast::GenericArgs::AngleBracketed(ref data) => {
+            if data.args.is_empty() {
+                Some("".to_owned())
+            } else {
+                let args = data
+                    .args
+                    .iter()
+                    .map(|x| match x {
+                        ast::AngleBracketedArg::Arg(generic_arg) => {
+                            SegmentParam::from_generic_arg(generic_arg)
+                        }
+                        ast::AngleBracketedArg::Constraint(constraint) => {
+                            SegmentParam::Binding(constraint)
+                        }
+                    })
+                    .collect::<Vec<_>>();
 
-            overflow::rewrite_with_angle_brackets(context, "", args.iter(), shape, span)
+                overflow::rewrite_with_angle_brackets(context, "", args.iter(), shape, span)
+            }
         }
         ast::GenericArgs::Parenthesized(ref data) => format_function_type(
             data.inputs.iter().map(|x| &**x),
@@ -495,7 +512,7 @@ fn rewrite_generic_args(
             context,
             shape,
         ),
-        _ => Some("".to_owned()),
+        ast::GenericArgs::ParenthesizedElided(..) => Some("(..)".to_owned()),
     }
 }
 
@@ -562,9 +579,10 @@ impl Rewrite for ast::GenericBound {
                     .map(|s| format!("{constness}{asyncness}{polarity}{s}"))
                     .map(|s| if has_paren { format!("({})", s) } else { s })
             }
+            ast::GenericBound::Use(ref args, span) => {
+                overflow::rewrite_with_angle_brackets(context, "use", args.iter(), shape, span)
+            }
             ast::GenericBound::Outlives(ref lifetime) => lifetime.rewrite(context, shape),
-            // FIXME(precise_capturing): Should implement formatting before stabilization.
-            ast::GenericBound::Use(..) => None,
         }
     }
 }
@@ -693,10 +711,12 @@ impl Rewrite for ast::Ty {
                 };
                 let mut res = bounds.rewrite(context, shape)?;
                 // We may have falsely removed a trailing `+` inside macro call.
-                if context.inside_macro() && bounds.len() == 1 {
-                    if context.snippet(self.span).ends_with('+') && !res.ends_with('+') {
-                        res.push('+');
-                    }
+                if context.inside_macro()
+                    && bounds.len() == 1
+                    && context.snippet(self.span).ends_with('+')
+                    && !res.ends_with('+')
+                {
+                    res.push('+');
                 }
                 Some(format!("{prefix}{res}"))
             }
@@ -929,9 +949,7 @@ fn rewrite_bare_fn(
 fn is_generic_bounds_in_order(generic_bounds: &[ast::GenericBound]) -> bool {
     let is_trait = |b: &ast::GenericBound| match b {
         ast::GenericBound::Outlives(..) => false,
-        ast::GenericBound::Trait(..) => true,
-        // FIXME(precise_capturing): This ordering fn should be reworked.
-        ast::GenericBound::Use(..) => false,
+        ast::GenericBound::Trait(..) | ast::GenericBound::Use(..) => true,
     };
     let is_lifetime = |b: &ast::GenericBound| !is_trait(b);
     let last_trait_index = generic_bounds.iter().rposition(is_trait);
@@ -965,9 +983,8 @@ fn join_bounds_inner(
     let generic_bounds_in_order = is_generic_bounds_in_order(items);
     let is_bound_extendable = |s: &str, b: &ast::GenericBound| match b {
         ast::GenericBound::Outlives(..) => true,
-        ast::GenericBound::Trait(..) => last_line_extendable(s),
-        // FIXME(precise_capturing): This ordering fn should be reworked.
-        ast::GenericBound::Use(..) => true,
+        // We treat `use<>` like a trait bound here.
+        ast::GenericBound::Trait(..) | ast::GenericBound::Use(..) => last_line_extendable(s),
     };
 
     // Whether a GenericBound item is a PathSegment segment that includes internal array
@@ -989,6 +1006,7 @@ fn join_bounds_inner(
                 }
             }
         }
+        ast::GenericBound::Use(args, _) => args.len() > 1,
         _ => false,
     };
 
diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs
index 7a0c68c214c..1de9f5a9524 100644
--- a/src/tools/rustfmt/src/visitor.rs
+++ b/src/tools/rustfmt/src/visitor.rs
@@ -81,7 +81,7 @@ pub(crate) struct FmtVisitor<'a> {
     pub(crate) snippet_provider: &'a SnippetProvider,
     pub(crate) line_number: usize,
     /// List of 1-based line ranges which were annotated with skip
-    /// Both bounds are inclusifs.
+    /// Both bounds are inclusive.
     pub(crate) skipped_range: Rc<RefCell<Vec<(usize, usize)>>>,
     pub(crate) macro_rewrite_failure: bool,
     pub(crate) report: FormatReport,
diff --git a/src/tools/rustfmt/tests/config/issue-5801-v1.toml b/src/tools/rustfmt/tests/config/issue-5801-v1.toml
new file mode 100644
index 00000000000..8695df0099e
--- /dev/null
+++ b/src/tools/rustfmt/tests/config/issue-5801-v1.toml
@@ -0,0 +1,3 @@
+max_width = 120
+version = "One"
+attr_fn_like_width = 120
\ No newline at end of file
diff --git a/src/tools/rustfmt/tests/config/issue-5801-v2.toml b/src/tools/rustfmt/tests/config/issue-5801-v2.toml
new file mode 100644
index 00000000000..948f4fb66bf
--- /dev/null
+++ b/src/tools/rustfmt/tests/config/issue-5801-v2.toml
@@ -0,0 +1,3 @@
+max_width = 120
+version = "Two"
+attr_fn_like_width = 120
\ No newline at end of file
diff --git a/src/tools/rustfmt/tests/mod-resolver/skip-files-issue-5065/main.rs b/src/tools/rustfmt/tests/mod-resolver/skip-files-issue-5065/main.rs
index 3122e4f220f..f102bf9d181 100644
--- a/src/tools/rustfmt/tests/mod-resolver/skip-files-issue-5065/main.rs
+++ b/src/tools/rustfmt/tests/mod-resolver/skip-files-issue-5065/main.rs
@@ -6,4 +6,4 @@ mod one;
 fn main() {println!("Hello, world!");
 }
 
-// trailing commet
+// trailing comment
diff --git a/src/tools/rustfmt/tests/rustfmt/main.rs b/src/tools/rustfmt/tests/rustfmt/main.rs
index e66fad1e7fa..58cf0e5e4db 100644
--- a/src/tools/rustfmt/tests/rustfmt/main.rs
+++ b/src/tools/rustfmt/tests/rustfmt/main.rs
@@ -176,7 +176,14 @@ fn rustfmt_emits_error_on_line_overflow_true() {
 #[test]
 #[allow(non_snake_case)]
 fn dont_emit_ICE() {
-    let files = ["tests/target/issue_5728.rs", "tests/target/issue_5729.rs", "tests/target/issue_6082.rs"];
+    let files = [
+        "tests/target/issue_5728.rs",
+        "tests/target/issue_5729.rs",
+        "tests/target/issue-5885.rs",
+        "tests/target/issue_6082.rs",
+        "tests/target/issue_6069.rs",
+        "tests/target/issue-6105.rs",
+    ];
 
     for file in files {
         let args = [file];
@@ -184,3 +191,19 @@ fn dont_emit_ICE() {
         assert!(!stderr.contains("thread 'main' panicked"));
     }
 }
+
+#[test]
+fn rustfmt_emits_error_when_control_brace_style_is_always_next_line() {
+    // See also https://github.com/rust-lang/rustfmt/issues/5912
+    let args = [
+        "--config=color=Never",
+        "--config",
+        "control_brace_style=AlwaysNextLine",
+        "--config",
+        "match_arm_blocks=false",
+        "tests/target/issue_5912.rs",
+    ];
+
+    let (_stdout, stderr) = rustfmt(&args);
+    assert!(!stderr.contains("error[internal]: left behind trailing whitespace"))
+}
diff --git a/src/tools/rustfmt/tests/source/arrow_in_comments/arrow_in_single_comment.rs b/src/tools/rustfmt/tests/source/arrow_in_comments/arrow_in_single_comment.rs
new file mode 100644
index 00000000000..fb0576a4822
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/arrow_in_comments/arrow_in_single_comment.rs
@@ -0,0 +1,10 @@
+// rustfmt-version: Two
+fn main() {
+    match a {
+        _ =>
+        // comment with =>
+                {
+            println!("A")
+        }
+    }
+}
diff --git a/src/tools/rustfmt/tests/source/arrow_in_comments/multiple_arrows.rs b/src/tools/rustfmt/tests/source/arrow_in_comments/multiple_arrows.rs
new file mode 100644
index 00000000000..fc696b309f2
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/arrow_in_comments/multiple_arrows.rs
@@ -0,0 +1,14 @@
+// rustfmt-version: Two
+fn main() {
+    match a {
+        _ => // comment with => 
+        match b {
+            // one goes to =>
+            one => {
+                println("1");
+            }
+            // two goes to =>
+            two => { println("2"); }
+        } 
+    }
+}
diff --git a/src/tools/rustfmt/tests/source/configs/format_generated_files/false_with_generated_marker_line_search_limit.rs b/src/tools/rustfmt/tests/source/configs/format_generated_files/false_with_generated_marker_line_search_limit.rs
new file mode 100644
index 00000000000..be03849fe10
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/configs/format_generated_files/false_with_generated_marker_line_search_limit.rs
@@ -0,0 +1,10 @@
+// rustfmt-format_generated_files: false
+// rustfmt-generated_marker_line_search_limit: 15
+
+fn main()
+{
+    println!("hello, world")
+    ;
+}
+
+// @generated
\ No newline at end of file
diff --git a/src/tools/rustfmt/tests/source/configs/format_generated_files/false_with_marker_out_scope_size.rs b/src/tools/rustfmt/tests/source/configs/format_generated_files/false_with_marker_out_scope_size.rs
new file mode 100644
index 00000000000..abb97e6259f
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/configs/format_generated_files/false_with_marker_out_scope_size.rs
@@ -0,0 +1,10 @@
+// rustfmt-format_generated_files: false
+// rustfmt-generated_marker_line_search_limit: 1
+
+fn main()
+{
+    println!("hello, world")
+    ;
+}
+
+// @generated
\ No newline at end of file
diff --git a/src/tools/rustfmt/tests/source/configs/format_generated_files/false_with_zero_search_limit.rs b/src/tools/rustfmt/tests/source/configs/format_generated_files/false_with_zero_search_limit.rs
new file mode 100644
index 00000000000..f6978d0f355
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/configs/format_generated_files/false_with_zero_search_limit.rs
@@ -0,0 +1,9 @@
+// rustfmt-format_generated_files: false
+// rustfmt-generated_marker_line_search_limit: 0
+
+// @generated
+fn main() {
+    println!("hello, world")
+    ;
+}
+// @generated
diff --git a/src/tools/rustfmt/tests/source/configs/format_generated_files/true_with_marker_in_scope_size.rs b/src/tools/rustfmt/tests/source/configs/format_generated_files/true_with_marker_in_scope_size.rs
new file mode 100644
index 00000000000..53cc116ec2b
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/configs/format_generated_files/true_with_marker_in_scope_size.rs
@@ -0,0 +1,10 @@
+// rustfmt-format_generated_files: true
+// rustfmt-generated_marker_line_search_limit: 20
+
+fn main()
+{
+    println!("hello, world")
+    ;
+}
+
+// @generated
diff --git a/src/tools/rustfmt/tests/source/configs/format_generated_files/true_with_marker_not_in_header.rs b/src/tools/rustfmt/tests/source/configs/format_generated_files/true_with_marker_not_in_header.rs
new file mode 100644
index 00000000000..8eff1a3b0ee
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/configs/format_generated_files/true_with_marker_not_in_header.rs
@@ -0,0 +1,9 @@
+// rustfmt-format_generated_files: true
+
+fn main()
+{
+    println!("hello, world")
+    ;
+}
+
+// @generated
\ No newline at end of file
diff --git a/src/tools/rustfmt/tests/source/issue-3805.rs b/src/tools/rustfmt/tests/source/issue-3805.rs
new file mode 100644
index 00000000000..a0289b57974
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue-3805.rs
@@ -0,0 +1,65 @@
+// rustfmt-version: Two
+// rustfmt-format_macro_matchers: true
+
+// From original issue example - Line length 101
+macro_rules! test {
+($aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr) => {{
+return;
+}};
+}
+
+// Spaces between the `{` and `}`
+macro_rules! test {
+($aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr) => {     {
+return;
+}      };
+}
+
+// Multi  `{}`
+macro_rules! test {
+($aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr) => {{{{
+return;
+}}}};
+}
+
+// Multi  `{}` with spaces
+macro_rules! test {
+($aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr) => {    {    {    {
+return;
+}     }     }    };
+}
+    
+// Line length 102
+macro_rules! test {
+($aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeiou:expr, $add:expr) => {{
+return;
+}};
+}
+
+// Line length 103
+macro_rules! test {
+($aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeioua:expr, $add:expr) => {{
+return;
+}};
+}
+
+// With extended macro body - Line length 101
+macro_rules! test {
+($aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr) => {{
+let VAR = "VALUE"; return VAR;
+}};
+}
+
+// With extended macro body - Line length 102
+macro_rules! test {
+($aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeiou:expr, $add:expr) => {{
+let VAR = "VALUE"; return VAR;
+}};
+}
+
+// With extended macro body - Line length 103
+macro_rules! test {
+($aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeioua:expr, $add:expr) => {{
+let VAR = "VALUE"; return VAR;
+}};
+}
diff --git a/src/tools/rustfmt/tests/source/issue-5801/attribute_unexpectedly_wraps_before_max_width.rs b/src/tools/rustfmt/tests/source/issue-5801/attribute_unexpectedly_wraps_before_max_width.rs
new file mode 100644
index 00000000000..59902c7bcce
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue-5801/attribute_unexpectedly_wraps_before_max_width.rs
@@ -0,0 +1,8 @@
+// rustfmt-config: issue-5801-v1.toml
+
+pub enum Severity {
+    #[something(AAAAAAAAAAAAA, BBBBBBBBBBBBBB, CCCCCCCCCCCCCCCC, DDDDDDDDDDDDD, EEEEEEEEEEEE, FFFFFFFFFFF, GGGGGGGGGGG)]
+    AttrsWillWrap,
+    #[something_else(hhhhhhhhhhhhhhhh, iiiiiiiiiiiiiiii, jjjjjjjjjjjjjjj, kkkkkkkkkkkkk, llllllllllll, mmmmmmmmmmmmmm)]
+    AttrsWontWrap,
+}
diff --git a/src/tools/rustfmt/tests/source/issue-5801/comment_unexpectedly_wraps_before_max_width.rs b/src/tools/rustfmt/tests/source/issue-5801/comment_unexpectedly_wraps_before_max_width.rs
new file mode 100644
index 00000000000..5847afd9560
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue-5801/comment_unexpectedly_wraps_before_max_width.rs
@@ -0,0 +1,17 @@
+// rustfmt-comment_width: 120
+// rustfmt-wrap_comments: true
+// rustfmt-max_width: 120
+// rustfmt-version: One
+
+/// This function is 120 columns wide and is left alone. This comment is 120 columns wide and the formatter is also fine
+fn my_super_cool_function_name(my_very_cool_argument_name: String, my_other_very_cool_argument_name: String) -> String {
+    unimplemented!()
+}
+
+pub enum Severity {
+    /// In version one, the below line got wrapped prematurely as we subtracted 1 to account for `,`. See issue #5801.
+    /// But here, this comment is 120 columns wide and the formatter wants to split it up onto two separate lines still.
+    Error,
+    /// This comment is 119 columns wide and works perfectly. Lorem ipsum. lorem ipsum. lorem ipsum. lorem ipsum lorem.
+    Warning,
+}
diff --git a/src/tools/rustfmt/tests/source/issue-5987/two.rs b/src/tools/rustfmt/tests/source/issue-5987/two.rs
new file mode 100644
index 00000000000..e20026b5565
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue-5987/two.rs
@@ -0,0 +1,13 @@
+// rustfmt-version: Two
+
+fn main() {
+    trace!(
+        "get some longer length in here yes yes {} {}",
+        "hello",
+        "world"
+    );
+    debug!(
+        "get some longer length in here yes yes {} {}",
+        "hello", "world"
+    );
+}
diff --git a/src/tools/rustfmt/tests/source/issue-6059/repro.rs b/src/tools/rustfmt/tests/source/issue-6059/repro.rs
new file mode 100644
index 00000000000..1dc62cc8d26
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue-6059/repro.rs
@@ -0,0 +1,3 @@
+fn float_range_tests() {
+    self.coords.x -= rng.gen_range(-self.radius / 2. .. self.radius / 2.);
+}
diff --git a/src/tools/rustfmt/tests/source/issue-6147/case_rustfmt_v1.rs b/src/tools/rustfmt/tests/source/issue-6147/case_rustfmt_v1.rs
new file mode 100644
index 00000000000..2ac2e0361c3
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue-6147/case_rustfmt_v1.rs
@@ -0,0 +1,20 @@
+// rustfmt-version: One
+
+pub fn main() {
+let a = Some(12);
+match a {
+#![attr1]
+#![attr2]
+#![attr3]
+_ => None,
+}
+
+{
+match a {
+#![attr1]
+#![attr2]
+#![attr3]
+_ => None,
+}
+}
+}
diff --git a/src/tools/rustfmt/tests/source/issue-6147/case_rustfmt_v2.rs b/src/tools/rustfmt/tests/source/issue-6147/case_rustfmt_v2.rs
new file mode 100644
index 00000000000..c1bf1ad4bf8
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue-6147/case_rustfmt_v2.rs
@@ -0,0 +1,20 @@
+// rustfmt-version: Two
+
+pub fn main() {
+let a = Some(12);
+match a {
+#![attr1]
+#![attr2]
+#![attr3]
+_ => None,
+}
+
+{
+match a {
+#![attr1]
+#![attr2]
+#![attr3]
+_ => None,
+}
+}
+}
diff --git a/src/tools/rustfmt/tests/source/issue_5912.rs b/src/tools/rustfmt/tests/source/issue_5912.rs
new file mode 100644
index 00000000000..2265fd2146c
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue_5912.rs
@@ -0,0 +1,15 @@
+// rustfmt-match_arm_blocks: false
+// rustfmt-control_brace_style: AlwaysNextLine
+
+fn foo() {
+    match 0 {
+        0 => {
+            aaaaaaaaaaaaaaaaaaaaaaaa
+                + bbbbbbbbbbbbbbbbbbbbbbbbb
+                + bbbbbbbbbbbbbbbbbbbbbbbbb
+                + bbbbbbbbbbbbbbbbbbbbbbbbb
+                + bbbbbbbbbbbbbbbbbbbbbbbbb
+        }
+        _ => 2,
+    }
+}
diff --git a/src/tools/rustfmt/tests/source/let_else.rs b/src/tools/rustfmt/tests/source/let_else.rs
index cb2859e805d..c589ab75cd3 100644
--- a/src/tools/rustfmt/tests/source/let_else.rs
+++ b/src/tools/rustfmt/tests/source/let_else.rs
@@ -117,8 +117,8 @@ fn unbreakable_initializer_expr_pre_formatting_length_through_initializer_expr_n
     // Break after the `=` and put the initializer expr on it's own line.
     // Because the initializer expr is multi-lined the else is placed on it's own line.
     // The initializer expr has a length of 91, which when indented on the next line
-    // The `(indent)init` line has a lengh of 99. This is the max length that the `init` can be
-    // before we start running into max_width issues. I suspect this is becuase the shape is
+    // The `(indent)init` line has a length of 99. This is the max length that the `init` can be
+    // before we start running into max_width issues. I suspect this is because the shape is
     // accounting for the `;` at the end of the `let-else` statement.
     let Some(x) = some_really_really_really_really_really_really_really_really_really_really_long_name______I else {return};
 
@@ -127,7 +127,7 @@ fn unbreakable_initializer_expr_pre_formatting_length_through_initializer_expr_n
     // Post Formatting:
     // Max length issues prevent us from formatting.
     // The initializer expr has a length of 92, which if it would be indented on the next line
-    // the `(indent)init` line has a lengh of 100 which == max_width of 100.
+    // the `(indent)init` line has a length of 100 which == max_width of 100.
     // One might expect formatting to succeed, but I suspect the reason we hit max_width issues is
     // because the Shape is accounting for the `;` at the end of the `let-else` statement.
     let Some(x) = some_really_really_really_really_really_really_really_really_really_really_really_long_nameJ else {return};
diff --git a/src/tools/rustfmt/tests/source/no_arg_with_commnet.rs b/src/tools/rustfmt/tests/source/no_arg_with_commnet.rs
index ea4ee0f1eee..41c3c6bea48 100644
--- a/src/tools/rustfmt/tests/source/no_arg_with_commnet.rs
+++ b/src/tools/rustfmt/tests/source/no_arg_with_commnet.rs
@@ -1,2 +1,2 @@
-fn foo(  /* cooment */
+fn foo(  /* comment */
 ) {}
diff --git a/src/tools/rustfmt/tests/source/precise-capturing.rs b/src/tools/rustfmt/tests/source/precise-capturing.rs
new file mode 100644
index 00000000000..b61cceeffe8
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/precise-capturing.rs
@@ -0,0 +1,9 @@
+fn hello() -> impl
+use<'a> + Sized {}
+
+fn all_three() -> impl Sized + use<'a> + 'a;
+
+fn pathological() -> impl use<'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a,
+'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a,
+'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 
+'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a, 'a> + Sized {}
diff --git a/src/tools/rustfmt/tests/target/arrow_in_comments/arrow_in_single_comment.rs b/src/tools/rustfmt/tests/target/arrow_in_comments/arrow_in_single_comment.rs
new file mode 100644
index 00000000000..deffdbeeaaf
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/arrow_in_comments/arrow_in_single_comment.rs
@@ -0,0 +1,10 @@
+// rustfmt-version: Two
+fn main() {
+    match a {
+        _ =>
+        // comment with =>
+        {
+            println!("A")
+        }
+    }
+}
diff --git a/src/tools/rustfmt/tests/target/arrow_in_comments/multiple_arrows.rs b/src/tools/rustfmt/tests/target/arrow_in_comments/multiple_arrows.rs
new file mode 100644
index 00000000000..b0443411816
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/arrow_in_comments/multiple_arrows.rs
@@ -0,0 +1,19 @@
+// rustfmt-version: Two
+fn main() {
+    match a {
+        _ =>
+        // comment with =>
+        {
+            match b {
+                // one goes to =>
+                one => {
+                    println("1");
+                }
+                // two goes to =>
+                two => {
+                    println("2");
+                }
+            }
+        }
+    }
+}
diff --git a/src/tools/rustfmt/tests/target/configs/format_generated_files/false_with_generated_marker_line_search_limit.rs b/src/tools/rustfmt/tests/target/configs/format_generated_files/false_with_generated_marker_line_search_limit.rs
new file mode 100644
index 00000000000..be03849fe10
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/configs/format_generated_files/false_with_generated_marker_line_search_limit.rs
@@ -0,0 +1,10 @@
+// rustfmt-format_generated_files: false
+// rustfmt-generated_marker_line_search_limit: 15
+
+fn main()
+{
+    println!("hello, world")
+    ;
+}
+
+// @generated
\ No newline at end of file
diff --git a/src/tools/rustfmt/tests/target/configs/format_generated_files/false_with_marker_out_scope_size.rs b/src/tools/rustfmt/tests/target/configs/format_generated_files/false_with_marker_out_scope_size.rs
new file mode 100644
index 00000000000..93405896a1d
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/configs/format_generated_files/false_with_marker_out_scope_size.rs
@@ -0,0 +1,8 @@
+// rustfmt-format_generated_files: false
+// rustfmt-generated_marker_line_search_limit: 1
+
+fn main() {
+    println!("hello, world");
+}
+
+// @generated
diff --git a/src/tools/rustfmt/tests/target/configs/format_generated_files/false_with_zero_search_limit.rs b/src/tools/rustfmt/tests/target/configs/format_generated_files/false_with_zero_search_limit.rs
new file mode 100644
index 00000000000..6acd46ed2eb
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/configs/format_generated_files/false_with_zero_search_limit.rs
@@ -0,0 +1,8 @@
+// rustfmt-format_generated_files: false
+// rustfmt-generated_marker_line_search_limit: 0
+
+// @generated
+fn main() {
+    println!("hello, world");
+}
+// @generated
diff --git a/src/tools/rustfmt/tests/target/configs/format_generated_files/true_with_marker_in_scope_size.rs b/src/tools/rustfmt/tests/target/configs/format_generated_files/true_with_marker_in_scope_size.rs
new file mode 100644
index 00000000000..03bfdfd1c59
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/configs/format_generated_files/true_with_marker_in_scope_size.rs
@@ -0,0 +1,8 @@
+// rustfmt-format_generated_files: true
+// rustfmt-generated_marker_line_search_limit: 20
+
+fn main() {
+    println!("hello, world");
+}
+
+// @generated
diff --git a/src/tools/rustfmt/tests/target/configs/format_generated_files/true_with_marker_not_in_header.rs b/src/tools/rustfmt/tests/target/configs/format_generated_files/true_with_marker_not_in_header.rs
new file mode 100644
index 00000000000..3b6280b350e
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/configs/format_generated_files/true_with_marker_not_in_header.rs
@@ -0,0 +1,7 @@
+// rustfmt-format_generated_files: true
+
+fn main() {
+    println!("hello, world");
+}
+
+// @generated
diff --git a/src/tools/rustfmt/tests/target/impl.rs b/src/tools/rustfmt/tests/target/impl.rs
index f37fbcf1fcb..10de0ecde56 100644
--- a/src/tools/rustfmt/tests/target/impl.rs
+++ b/src/tools/rustfmt/tests/target/impl.rs
@@ -32,6 +32,11 @@ where
 {
 }
 
+// #5941
+impl T where (): Clone // Should not add comma to comment
+{
+}
+
 // #1823
 default impl Trait for X {}
 default unsafe impl Trait for Y {}
diff --git a/src/tools/rustfmt/tests/target/issue-3805.rs b/src/tools/rustfmt/tests/target/issue-3805.rs
new file mode 100644
index 00000000000..a247a43fe6d
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-3805.rs
@@ -0,0 +1,94 @@
+// rustfmt-version: Two
+// rustfmt-format_macro_matchers: true
+
+// From original issue example - Line length 101
+macro_rules! test {
+    (
+        $aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr
+    ) => {{
+        return;
+    }};
+}
+
+// Spaces between the `{` and `}`
+macro_rules! test {
+    (
+        $aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr
+    ) => {{
+        return;
+    }};
+}
+
+// Multi  `{}`
+macro_rules! test {
+    (
+        $aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr
+    ) => {{
+        {
+            {
+                return;
+            }
+        }
+    }};
+}
+
+// Multi  `{}` with spaces
+macro_rules! test {
+    (
+        $aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr
+    ) => {{
+        {
+            {
+                return;
+            }
+        }
+    }};
+}
+
+// Line length 102
+macro_rules! test {
+    (
+        $aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeiou:expr, $add:expr
+    ) => {{
+        return;
+    }};
+}
+
+// Line length 103
+macro_rules! test {
+    (
+        $aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeioua:expr, $add:expr
+    ) => {{
+        return;
+    }};
+}
+
+// With extended macro body - Line length 101
+macro_rules! test {
+    (
+        $aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr
+    ) => {{
+        let VAR = "VALUE";
+        return VAR;
+    }};
+}
+
+// With extended macro body - Line length 102
+macro_rules! test {
+    (
+        $aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeiou:expr, $add:expr
+    ) => {{
+        let VAR = "VALUE";
+        return VAR;
+    }};
+}
+
+// With extended macro body - Line length 103
+macro_rules! test {
+    (
+        $aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeioua:expr, $add:expr
+    ) => {{
+        let VAR = "VALUE";
+        return VAR;
+    }};
+}
diff --git a/src/tools/rustfmt/tests/target/issue-5801/attribute_does_not_wrap_within_max_width.rs b/src/tools/rustfmt/tests/target/issue-5801/attribute_does_not_wrap_within_max_width.rs
new file mode 100644
index 00000000000..e3b6f3b37f5
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5801/attribute_does_not_wrap_within_max_width.rs
@@ -0,0 +1,8 @@
+// rustfmt-config: issue-5801-v2.toml
+
+pub enum Severity {
+    #[something(AAAAAAAAAAAAA, BBBBBBBBBBBBBB, CCCCCCCCCCCCCCCC, DDDDDDDDDDDDD, EEEEEEEEEEEE, FFFFFFFFFFF, GGGGGGGGGGG)]
+    AttrsWillWrap,
+    #[something_else(hhhhhhhhhhhhhhhh, iiiiiiiiiiiiiiii, jjjjjjjjjjjjjjj, kkkkkkkkkkkkk, llllllllllll, mmmmmmmmmmmmmm)]
+    AttrsWontWrap,
+}
diff --git a/src/tools/rustfmt/tests/target/issue-5801/attribute_unexpectedly_wraps_before_max_width.rs b/src/tools/rustfmt/tests/target/issue-5801/attribute_unexpectedly_wraps_before_max_width.rs
new file mode 100644
index 00000000000..89676666225
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5801/attribute_unexpectedly_wraps_before_max_width.rs
@@ -0,0 +1,16 @@
+// rustfmt-config: issue-5801-v1.toml
+
+pub enum Severity {
+    #[something(
+        AAAAAAAAAAAAA,
+        BBBBBBBBBBBBBB,
+        CCCCCCCCCCCCCCCC,
+        DDDDDDDDDDDDD,
+        EEEEEEEEEEEE,
+        FFFFFFFFFFF,
+        GGGGGGGGGGG
+    )]
+    AttrsWillWrap,
+    #[something_else(hhhhhhhhhhhhhhhh, iiiiiiiiiiiiiiii, jjjjjjjjjjjjjjj, kkkkkkkkkkkkk, llllllllllll, mmmmmmmmmmmmmm)]
+    AttrsWontWrap,
+}
diff --git a/src/tools/rustfmt/tests/target/issue-5801/comment_does_not_wrap_within_max_width.rs b/src/tools/rustfmt/tests/target/issue-5801/comment_does_not_wrap_within_max_width.rs
new file mode 100644
index 00000000000..9f294751108
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5801/comment_does_not_wrap_within_max_width.rs
@@ -0,0 +1,16 @@
+// rustfmt-comment_width: 120
+// rustfmt-wrap_comments: true
+// rustfmt-max_width: 120
+// rustfmt-version: Two
+
+/// This function is 120 columns wide and is left alone. This comment is 120 columns wide and the formatter is also fine
+fn my_super_cool_function_name(my_very_cool_argument_name: String, my_other_very_cool_argument_name: String) -> String {
+    unimplemented!()
+}
+
+pub enum Severity {
+    /// But here, this comment is 120 columns wide and the formatter wants to split it up onto two separate lines still.
+    Error,
+    /// This comment is 119 columns wide and works perfectly. Lorem ipsum. lorem ipsum. lorem ipsum. lorem ipsum lorem.
+    Warning,
+}
diff --git a/src/tools/rustfmt/tests/target/issue-5801/comment_unexpectedly_wraps_before_max_width.rs b/src/tools/rustfmt/tests/target/issue-5801/comment_unexpectedly_wraps_before_max_width.rs
new file mode 100644
index 00000000000..dd839dd4548
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5801/comment_unexpectedly_wraps_before_max_width.rs
@@ -0,0 +1,18 @@
+// rustfmt-comment_width: 120
+// rustfmt-wrap_comments: true
+// rustfmt-max_width: 120
+// rustfmt-version: One
+
+/// This function is 120 columns wide and is left alone. This comment is 120 columns wide and the formatter is also fine
+fn my_super_cool_function_name(my_very_cool_argument_name: String, my_other_very_cool_argument_name: String) -> String {
+    unimplemented!()
+}
+
+pub enum Severity {
+    /// In version one, the below line got wrapped prematurely as we subtracted 1 to account for `,`. See issue #5801.
+    /// But here, this comment is 120 columns wide and the formatter wants to split it up onto two separate lines
+    /// still.
+    Error,
+    /// This comment is 119 columns wide and works perfectly. Lorem ipsum. lorem ipsum. lorem ipsum. lorem ipsum lorem.
+    Warning,
+}
diff --git a/src/tools/rustfmt/tests/target/issue-5885.rs b/src/tools/rustfmt/tests/target/issue-5885.rs
new file mode 100644
index 00000000000..85a659cbb47
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5885.rs
@@ -0,0 +1,3 @@
+fn main() {
+    println!("{}", builtin # offset_of(A, 0. 1.1.1));
+}
diff --git a/src/tools/rustfmt/tests/target/issue-5987/one.rs b/src/tools/rustfmt/tests/target/issue-5987/one.rs
new file mode 100644
index 00000000000..3c995ed28ba
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5987/one.rs
@@ -0,0 +1,13 @@
+// rustfmt-version: One
+
+fn main() {
+    trace!(
+        "get some longer length in here yes yes {} {}",
+        "hello",
+        "world"
+    );
+    debug!(
+        "get some longer length in here yes yes {} {}",
+        "hello", "world"
+    );
+}
diff --git a/src/tools/rustfmt/tests/target/issue-5987/two.rs b/src/tools/rustfmt/tests/target/issue-5987/two.rs
new file mode 100644
index 00000000000..8fd92fc179e
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5987/two.rs
@@ -0,0 +1,12 @@
+// rustfmt-version: Two
+
+fn main() {
+    trace!(
+        "get some longer length in here yes yes {} {}",
+        "hello", "world"
+    );
+    debug!(
+        "get some longer length in here yes yes {} {}",
+        "hello", "world"
+    );
+}
diff --git a/src/tools/rustfmt/tests/target/issue-6059/additional.rs b/src/tools/rustfmt/tests/target/issue-6059/additional.rs
new file mode 100644
index 00000000000..fe708dcbdd3
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-6059/additional.rs
@@ -0,0 +1,6 @@
+fn float_range_tests() {
+    let _range = 3. / 2. ..4.;
+    let _range = 3.0 / 2. ..4.0;
+    let _range = 3.0 / 2.0..4.0;
+    let _range = 3. / 2.0..4.0;
+}
diff --git a/src/tools/rustfmt/tests/target/issue-6059/repro.rs b/src/tools/rustfmt/tests/target/issue-6059/repro.rs
new file mode 100644
index 00000000000..e8744c9ffcf
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-6059/repro.rs
@@ -0,0 +1,3 @@
+fn float_range_tests() {
+    self.coords.x -= rng.gen_range(-self.radius / 2. ..self.radius / 2.);
+}
diff --git a/src/tools/rustfmt/tests/target/issue-6105.rs b/src/tools/rustfmt/tests/target/issue-6105.rs
new file mode 100644
index 00000000000..1eb0ce89f78
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-6105.rs
@@ -0,0 +1 @@
+const _: () = builtin # offset_of(x, x);
diff --git a/src/tools/rustfmt/tests/target/issue-6147/case_rustfmt_v1.rs b/src/tools/rustfmt/tests/target/issue-6147/case_rustfmt_v1.rs
new file mode 100644
index 00000000000..75800012c63
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-6147/case_rustfmt_v1.rs
@@ -0,0 +1,20 @@
+// rustfmt-version: One
+
+pub fn main() {
+    let a = Some(12);
+    match a {
+        #![attr1]
+    #![attr2]
+    #![attr3]
+        _ => None,
+    }
+
+    {
+        match a {
+            #![attr1]
+        #![attr2]
+        #![attr3]
+            _ => None,
+        }
+    }
+}
diff --git a/src/tools/rustfmt/tests/target/issue-6147/case_rustfmt_v2.rs b/src/tools/rustfmt/tests/target/issue-6147/case_rustfmt_v2.rs
new file mode 100644
index 00000000000..5e4220e7306
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-6147/case_rustfmt_v2.rs
@@ -0,0 +1,20 @@
+// rustfmt-version: Two
+
+pub fn main() {
+    let a = Some(12);
+    match a {
+        #![attr1]
+        #![attr2]
+        #![attr3]
+        _ => None,
+    }
+
+    {
+        match a {
+            #![attr1]
+            #![attr2]
+            #![attr3]
+            _ => None,
+        }
+    }
+}
diff --git a/src/tools/rustfmt/tests/target/issue_5912.rs b/src/tools/rustfmt/tests/target/issue_5912.rs
new file mode 100644
index 00000000000..835f2aba971
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue_5912.rs
@@ -0,0 +1,15 @@
+// rustfmt-match_arm_blocks: false
+// rustfmt-control_brace_style: AlwaysNextLine
+
+fn foo() {
+    match 0
+    {
+        0 =>
+            aaaaaaaaaaaaaaaaaaaaaaaa
+                + bbbbbbbbbbbbbbbbbbbbbbbbb
+                + bbbbbbbbbbbbbbbbbbbbbbbbb
+                + bbbbbbbbbbbbbbbbbbbbbbbbb
+                + bbbbbbbbbbbbbbbbbbbbbbbbb,
+        _ => 2,
+    }
+}
diff --git a/src/tools/rustfmt/tests/target/issue_6069.rs b/src/tools/rustfmt/tests/target/issue_6069.rs
new file mode 100644
index 00000000000..d866ce7c646
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue_6069.rs
@@ -0,0 +1,3 @@
+// `Foó` as written here ends with ASCII 6F `'o'` followed by `'\u{0301}'` COMBINING ACUTE ACCENT.
+// The compiler normalizes that combination to NFC form, `'\u{00F3}'` LATIN SMALL LETTER O WITH ACUTE.
+trait Foó: Bar {}
diff --git a/src/tools/rustfmt/tests/target/issue_6158.rs b/src/tools/rustfmt/tests/target/issue_6158.rs
new file mode 100644
index 00000000000..82bb7d9fa05
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue_6158.rs
@@ -0,0 +1,7 @@
+fn main() {
+    const {
+        #![allow(clippy::assertions_on_constants)]
+
+        assert!(1 < 2);
+    }
+}
diff --git a/src/tools/rustfmt/tests/target/issue_6159.rs b/src/tools/rustfmt/tests/target/issue_6159.rs
new file mode 100644
index 00000000000..49fd539d3ef
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue_6159.rs
@@ -0,0 +1,3 @@
+fn main() {
+    builtin # type_ascribe(10, usize)
+}
diff --git a/src/tools/rustfmt/tests/target/let_else.rs b/src/tools/rustfmt/tests/target/let_else.rs
index f6560e85462..528d2929734 100644
--- a/src/tools/rustfmt/tests/target/let_else.rs
+++ b/src/tools/rustfmt/tests/target/let_else.rs
@@ -180,8 +180,8 @@ fn unbreakable_initializer_expr_pre_formatting_length_through_initializer_expr_n
     // Break after the `=` and put the initializer expr on it's own line.
     // Because the initializer expr is multi-lined the else is placed on it's own line.
     // The initializer expr has a length of 91, which when indented on the next line
-    // The `(indent)init` line has a lengh of 99. This is the max length that the `init` can be
-    // before we start running into max_width issues. I suspect this is becuase the shape is
+    // The `(indent)init` line has a length of 99. This is the max length that the `init` can be
+    // before we start running into max_width issues. I suspect this is because the shape is
     // accounting for the `;` at the end of the `let-else` statement.
     let Some(x) =
         some_really_really_really_really_really_really_really_really_really_really_long_name______I
@@ -194,7 +194,7 @@ fn unbreakable_initializer_expr_pre_formatting_length_through_initializer_expr_n
     // Post Formatting:
     // Max length issues prevent us from formatting.
     // The initializer expr has a length of 92, which if it would be indented on the next line
-    // the `(indent)init` line has a lengh of 100 which == max_width of 100.
+    // the `(indent)init` line has a length of 100 which == max_width of 100.
     // One might expect formatting to succeed, but I suspect the reason we hit max_width issues is
     // because the Shape is accounting for the `;` at the end of the `let-else` statement.
     let Some(x) = some_really_really_really_really_really_really_really_really_really_really_really_long_nameJ else {return};
diff --git a/src/tools/rustfmt/tests/target/no_arg_with_commnet.rs b/src/tools/rustfmt/tests/target/no_arg_with_commnet.rs
index 69f61b60f29..21802d87f47 100644
--- a/src/tools/rustfmt/tests/target/no_arg_with_commnet.rs
+++ b/src/tools/rustfmt/tests/target/no_arg_with_commnet.rs
@@ -1 +1 @@
-fn foo(/* cooment */) {}
+fn foo(/* comment */) {}
diff --git a/src/tools/rustfmt/tests/target/precise-capturing.rs b/src/tools/rustfmt/tests/target/precise-capturing.rs
new file mode 100644
index 00000000000..d21374f44c1
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/precise-capturing.rs
@@ -0,0 +1,55 @@
+fn hello() -> impl use<'a> + Sized {}
+
+fn all_three() -> impl Sized + use<'a> + 'a;
+
+fn pathological() -> impl use<
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+    'a,
+> + Sized {
+}
diff --git a/src/tools/rustfmt/tests/target/return-type-notation.rs b/src/tools/rustfmt/tests/target/return-type-notation.rs
new file mode 100644
index 00000000000..0f26e7e272b
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/return-type-notation.rs
@@ -0,0 +1,10 @@
+fn rtn()
+where
+    T: Trait<method(..): Send + 'static>,
+    T::method(..): Send + 'static,
+{
+}
+
+fn test() {
+    let x: T::method(..);
+}
diff --git a/src/tools/rustfmt/tests/target/unsafe_attributes.rs b/src/tools/rustfmt/tests/target/unsafe_attributes.rs
new file mode 100644
index 00000000000..a05bedc751a
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/unsafe_attributes.rs
@@ -0,0 +1,34 @@
+#![feature(unsafe_attributes)]
+// https://github.com/rust-lang/rust/issues/123757
+//
+#![simple_ident]
+#![simple::path]
+#![simple_ident_expr = ""]
+#![simple::path::Expr = ""]
+#![simple_ident_tt(a b c)]
+#![simple_ident_tt[a b c]]
+#![simple_ident_tt{a b c}]
+#![simple::path::tt(a b c)]
+#![simple::path::tt[a b c]]
+#![simple::path::tt{a b c}]
+#![unsafe(simple_ident)]
+#![unsafe(simple::path)]
+#![unsafe(simple_ident_expr = "")]
+#![unsafe(simple::path::Expr = "")]
+#![unsafe(simple_ident_tt(a b c))]
+#![unsafe(simple_ident_tt[a b c])]
+#![unsafe(simple_ident_tt{a b c})]
+#![unsafe(simple::path::tt(a b c))]
+#![unsafe(simple::path::tt[a b c])]
+#![unsafe(simple::path::tt{a b c})]
+// I don't think `safe` attributes are a thing, but adding these formatting cases here just in case
+#![safe(simple_ident)]
+#![safe(simple::path)]
+#![safe(simple_ident_expr = "")]
+#![safe(simple::path::Expr = "")]
+#![safe(simple_ident_tt(a b c))]
+#![safe(simple_ident_tt[a b c])]
+#![safe(simple_ident_tt{a b c})]
+#![safe(simple::path::tt(a b c))]
+#![safe(simple::path::tt[a b c])]
+#![safe(simple::path::tt{a b c})]
diff --git a/src/tools/rustfmt/tests/target/unsafe_extern_blocks.rs b/src/tools/rustfmt/tests/target/unsafe_extern_blocks.rs
new file mode 100644
index 00000000000..66b4e1604d8
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/unsafe_extern_blocks.rs
@@ -0,0 +1,18 @@
+// See tracking issue for unsafe_extern_blocks
+// https://github.com/rust-lang/rust/issues/123743
+
+#![feature(unsafe_extern_blocks)]
+
+safe static TEST1: i32;
+
+unsafe extern "C" {
+    safe static TEST2: i32;
+    unsafe static TEST3: i32;
+    static TEST4: i32;
+
+    pub safe static TEST5: i32;
+    pub unsafe static TEST6: i32;
+    pub static TEST7: i32;
+
+    safe fn test1(i: i32);
+}
diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml
index 63963b0bd1c..1acdf9fbc7f 100644
--- a/src/tools/tidy/Cargo.toml
+++ b/src/tools/tidy/Cargo.toml
@@ -5,6 +5,7 @@ edition = "2021"
 autobins = false
 
 [dependencies]
+build_helper = { path = "../build_helper" }
 cargo_metadata = "0.15"
 regex = "1"
 miropt-test-tools = { path = "../miropt-test-tools" }
@@ -13,6 +14,8 @@ ignore = "0.4.18"
 semver = "1.0"
 termcolor = "1.1.3"
 rustc-hash = "1.1.0"
+fluent-syntax = "0.11.1"
+similar = "2.5.0"
 
 [[bin]]
 name = "rust-tidy"
diff --git a/src/tools/tidy/config/requirements.in b/src/tools/tidy/config/requirements.in
index 047617c6559..8938dc03243 100644
--- a/src/tools/tidy/config/requirements.in
+++ b/src/tools/tidy/config/requirements.in
@@ -6,5 +6,6 @@
 # Note: this generation step should be run with the oldest supported python
 # version (currently 3.9) to ensure backward compatibility
 
-black==23.3.0
-ruff==0.0.272
+black==24.4.2
+ruff==0.4.9
+clang-format==18.1.7
diff --git a/src/tools/tidy/config/requirements.txt b/src/tools/tidy/config/requirements.txt
index a53c98cac7a..790eabf5cf8 100644
--- a/src/tools/tidy/config/requirements.txt
+++ b/src/tools/tidy/config/requirements.txt
@@ -4,32 +4,46 @@
 #
 #    pip-compile --generate-hashes --strip-extras src/tools/tidy/config/requirements.in
 #
-black==23.3.0 \
-    --hash=sha256:064101748afa12ad2291c2b91c960be28b817c0c7eaa35bec09cc63aa56493c5 \
-    --hash=sha256:0945e13506be58bf7db93ee5853243eb368ace1c08a24c65ce108986eac65915 \
-    --hash=sha256:11c410f71b876f961d1de77b9699ad19f939094c3a677323f43d7a29855fe326 \
-    --hash=sha256:1c7b8d606e728a41ea1ccbd7264677e494e87cf630e399262ced92d4a8dac940 \
-    --hash=sha256:1d06691f1eb8de91cd1b322f21e3bfc9efe0c7ca1f0e1eb1db44ea367dff656b \
-    --hash=sha256:3238f2aacf827d18d26db07524e44741233ae09a584273aa059066d644ca7b30 \
-    --hash=sha256:32daa9783106c28815d05b724238e30718f34155653d4d6e125dc7daec8e260c \
-    --hash=sha256:35d1381d7a22cc5b2be2f72c7dfdae4072a3336060635718cc7e1ede24221d6c \
-    --hash=sha256:3a150542a204124ed00683f0db1f5cf1c2aaaa9cc3495b7a3b5976fb136090ab \
-    --hash=sha256:48f9d345675bb7fbc3dd85821b12487e1b9a75242028adad0333ce36ed2a6d27 \
-    --hash=sha256:50cb33cac881766a5cd9913e10ff75b1e8eb71babf4c7104f2e9c52da1fb7de2 \
-    --hash=sha256:562bd3a70495facf56814293149e51aa1be9931567474993c7942ff7d3533961 \
-    --hash=sha256:67de8d0c209eb5b330cce2469503de11bca4085880d62f1628bd9972cc3366b9 \
-    --hash=sha256:6b39abdfb402002b8a7d030ccc85cf5afff64ee90fa4c5aebc531e3ad0175ddb \
-    --hash=sha256:6f3c333ea1dd6771b2d3777482429864f8e258899f6ff05826c3a4fcc5ce3f70 \
-    --hash=sha256:714290490c18fb0126baa0fca0a54ee795f7502b44177e1ce7624ba1c00f2331 \
-    --hash=sha256:7c3eb7cea23904399866c55826b31c1f55bbcd3890ce22ff70466b907b6775c2 \
-    --hash=sha256:92c543f6854c28a3c7f39f4d9b7694f9a6eb9d3c5e2ece488c327b6e7ea9b266 \
-    --hash=sha256:a6f6886c9869d4daae2d1715ce34a19bbc4b95006d20ed785ca00fa03cba312d \
-    --hash=sha256:a8a968125d0a6a404842fa1bf0b349a568634f856aa08ffaff40ae0dfa52e7c6 \
-    --hash=sha256:c7ab5790333c448903c4b721b59c0d80b11fe5e9803d8703e84dcb8da56fec1b \
-    --hash=sha256:e114420bf26b90d4b9daa597351337762b63039752bdf72bf361364c1aa05925 \
-    --hash=sha256:e198cf27888ad6f4ff331ca1c48ffc038848ea9f031a3b40ba36aced7e22f2c8 \
-    --hash=sha256:ec751418022185b0c1bb7d7736e6933d40bbb14c14a0abcf9123d1b159f98dd4 \
-    --hash=sha256:f0bd2f4a58d6666500542b26354978218a9babcdc972722f4bf90779524515f3
+black==24.4.2 \
+    --hash=sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474 \
+    --hash=sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1 \
+    --hash=sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0 \
+    --hash=sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8 \
+    --hash=sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96 \
+    --hash=sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1 \
+    --hash=sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04 \
+    --hash=sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021 \
+    --hash=sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94 \
+    --hash=sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d \
+    --hash=sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c \
+    --hash=sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7 \
+    --hash=sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c \
+    --hash=sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc \
+    --hash=sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7 \
+    --hash=sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d \
+    --hash=sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c \
+    --hash=sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741 \
+    --hash=sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce \
+    --hash=sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb \
+    --hash=sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063 \
+    --hash=sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e
+    # via -r src/tools/tidy/config/requirements.in
+clang-format==18.1.7 \
+    --hash=sha256:035204410f65d03f98cb81c9c39d6d193f9987917cc88de9d0dbd01f2aa9c302 \
+    --hash=sha256:05c482a854287a5d21f7567186c0bd4b8dbd4a871751e655a45849185f30b931 \
+    --hash=sha256:0b352ec51b291fe04c25a0f0ed15ba1a55b9c9c8eaa7fdf14de3d3585aef4f72 \
+    --hash=sha256:217526c8189c18fd175e19bb3e4da2d1bdf14a2bf79d97108c9b6a98d9938351 \
+    --hash=sha256:42d0b580ab7a45348155944adebe0bef53d1de9357b925830a59bbc351a25560 \
+    --hash=sha256:57090c40a8f0a898e0db8be150a19be2551302d5f5620d2a01de07e7c9220a53 \
+    --hash=sha256:607772cf474c1ebe0de44f44c1324e57a2d5b45a1d96d4aff166645532d99b43 \
+    --hash=sha256:a49c44d7cc00431be8285aa120a7a21fa0475786c03c53b04a26882c4e626a43 \
+    --hash=sha256:a62fca204293893badde0ab004df8b6df1d13eac4d452051554d9684d0a8254e \
+    --hash=sha256:a914592a51f77c3563563c7a8970f19bc1ed59174ab992f095a78f4e142382ac \
+    --hash=sha256:b3a0a09428cdd656ed87074543222a80660bc506407ed21b8e4bcb3d6d3a5a3c \
+    --hash=sha256:c151d42e6ac7c3cc03d7fec61bed3211ce8f75528e1efd8fc64bdb33840987b2 \
+    --hash=sha256:d6a2f051124d6ae506ba2a68accfe4ea4c8cb90d13b422c3131bb124413bac32 \
+    --hash=sha256:f4f77ac0f4f9a659213fedda0f2d216886c410132e6e7dd4b13f92b34e925554 \
+    --hash=sha256:f935d34152a2e11e55120eb9182862f432bc9789ab819f680c9f6db4edebf9e3
     # via -r src/tools/tidy/config/requirements.in
 click==8.1.3 \
     --hash=sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e \
@@ -47,28 +61,28 @@ pathspec==0.11.1 \
     --hash=sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687 \
     --hash=sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293
     # via black
-platformdirs==3.6.0 \
-    --hash=sha256:57e28820ca8094678b807ff529196506d7a21e17156cb1cddb3e74cebce54640 \
-    --hash=sha256:ffa199e3fbab8365778c4a10e1fbf1b9cd50707de826eb304b50e57ec0cc8d38
+platformdirs==4.2.2 \
+    --hash=sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee \
+    --hash=sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3
     # via black
-ruff==0.0.272 \
-    --hash=sha256:06b8ee4eb8711ab119db51028dd9f5384b44728c23586424fd6e241a5b9c4a3b \
-    --hash=sha256:1609b864a8d7ee75a8c07578bdea0a7db75a144404e75ef3162e0042bfdc100d \
-    --hash=sha256:19643d448f76b1eb8a764719072e9c885968971bfba872e14e7257e08bc2f2b7 \
-    --hash=sha256:273a01dc8c3c4fd4c2af7ea7a67c8d39bb09bce466e640dd170034da75d14cab \
-    --hash=sha256:27b2ea68d2aa69fff1b20b67636b1e3e22a6a39e476c880da1282c3e4bf6ee5a \
-    --hash=sha256:48eccf225615e106341a641f826b15224b8a4240b84269ead62f0afd6d7e2d95 \
-    --hash=sha256:677284430ac539bb23421a2b431b4ebc588097ef3ef918d0e0a8d8ed31fea216 \
-    --hash=sha256:691d72a00a99707a4e0b2846690961157aef7b17b6b884f6b4420a9f25cd39b5 \
-    --hash=sha256:86bc788245361a8148ff98667da938a01e1606b28a45e50ac977b09d3ad2c538 \
-    --hash=sha256:905ff8f3d6206ad56fcd70674453527b9011c8b0dc73ead27618426feff6908e \
-    --hash=sha256:9c4bfb75456a8e1efe14c52fcefb89cfb8f2a0d31ed8d804b82c6cf2dc29c42c \
-    --hash=sha256:a37ec80e238ead2969b746d7d1b6b0d31aa799498e9ba4281ab505b93e1f4b28 \
-    --hash=sha256:ae9b57546e118660175d45d264b87e9b4c19405c75b587b6e4d21e6a17bf4fdf \
-    --hash=sha256:bd2bbe337a3f84958f796c77820d55ac2db1e6753f39d1d1baed44e07f13f96d \
-    --hash=sha256:d5a208f8ef0e51d4746930589f54f9f92f84bb69a7d15b1de34ce80a7681bc00 \
-    --hash=sha256:dc406e5d756d932da95f3af082814d2467943631a587339ee65e5a4f4fbe83eb \
-    --hash=sha256:ee76b4f05fcfff37bd6ac209d1370520d509ea70b5a637bdf0a04d0c99e13dff
+ruff==0.4.9 \
+    --hash=sha256:06b60f91bfa5514bb689b500a25ba48e897d18fea14dce14b48a0c40d1635893 \
+    --hash=sha256:0e8e7b95673f22e0efd3571fb5b0cf71a5eaaa3cc8a776584f3b2cc878e46bff \
+    --hash=sha256:2d45ddc6d82e1190ea737341326ecbc9a61447ba331b0a8962869fcada758505 \
+    --hash=sha256:4555056049d46d8a381f746680db1c46e67ac3b00d714606304077682832998e \
+    --hash=sha256:5d5460f789ccf4efd43f265a58538a2c24dbce15dbf560676e430375f20a8198 \
+    --hash=sha256:673bddb893f21ab47a8334c8e0ea7fd6598ecc8e698da75bcd12a7b9d0a3206e \
+    --hash=sha256:732dd550bfa5d85af8c3c6cbc47ba5b67c6aed8a89e2f011b908fc88f87649db \
+    --hash=sha256:784d3ec9bd6493c3b720a0b76f741e6c2d7d44f6b2be87f5eef1ae8cc1d54c84 \
+    --hash=sha256:78de3fdb95c4af084087628132336772b1c5044f6e710739d440fc0bccf4d321 \
+    --hash=sha256:8064590fd1a50dcf4909c268b0e7c2498253273309ad3d97e4a752bb9df4f521 \
+    --hash=sha256:88bffe9c6a454bf8529f9ab9091c99490578a593cc9f9822b7fc065ee0712a06 \
+    --hash=sha256:8c1aff58c31948cc66d0b22951aa19edb5af0a3af40c936340cd32a8b1ab7438 \
+    --hash=sha256:98ec2775fd2d856dc405635e5ee4ff177920f2141b8e2d9eb5bd6efd50e80317 \
+    --hash=sha256:b262ed08d036ebe162123170b35703aaf9daffecb698cd367a8d585157732991 \
+    --hash=sha256:e0a22c4157e53d006530c902107c7f550b9233e9706313ab57b892d7197d8e52 \
+    --hash=sha256:e91175fbe48f8a2174c9aad70438fe9cb0a5732c4159b2a10a3565fea2d94cde \
+    --hash=sha256:f1cb0828ac9533ba0135d148d214e284711ede33640465e706772645483427e3
     # via -r src/tools/tidy/config/requirements.in
 tomli==2.0.1 \
     --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \
diff --git a/src/tools/tidy/config/ruff.toml b/src/tools/tidy/config/ruff.toml
index cf89ffd9ac7..c87c17f7833 100644
--- a/src/tools/tidy/config/ruff.toml
+++ b/src/tools/tidy/config/ruff.toml
@@ -1,17 +1,7 @@
 # Configuration for ruff python linter, run as part of tidy external tools
 
-# B (bugbear), E (pycodestyle, standard), EXE (executables) F (flakes, standard)
-# ERM for error messages would be beneficial at some point
-select = ["B", "E", "EXE", "F"]
-
-ignore = [
-    "E501", # line-too-long
-    "F403", # undefined-local-with-import-star
-    "F405", # undefined-local-with-import-star-usage
-]
-
 # lowest possible for ruff
-target-version = "py37"
+target-version = "py39"
 
 # Ignore all submodules
 extend-exclude = [
@@ -41,3 +31,14 @@ extend-exclude = [
     "../library/backtrace/",
     "../src/tools/rustc-perf/",
 ]
+
+[lint]
+# B (bugbear), E (pycodestyle, standard), EXE (executables) F (flakes, standard)
+# ERM for error messages would be beneficial at some point
+select = ["B", "E", "EXE", "F"]
+
+ignore = [
+    "E501", # line-too-long
+    "F403", # undefined-local-with-import-star
+    "F405", # undefined-local-with-import-star-usage
+]
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index 2b273b92ec2..33120cf93f9 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -9,37 +9,24 @@ run-make/c-unwind-abi-catch-lib-panic/Makefile
 run-make/c-unwind-abi-catch-panic/Makefile
 run-make/cat-and-grep-sanity-check/Makefile
 run-make/cdylib-dylib-linkage/Makefile
-run-make/cdylib-fewer-symbols/Makefile
-run-make/comment-section/Makefile
 run-make/compiler-lookup-paths-2/Makefile
 run-make/compiler-lookup-paths/Makefile
 run-make/compiler-rt-works-on-mingw/Makefile
-run-make/compressed-debuginfo/Makefile
 run-make/crate-hash-rustc-version/Makefile
-run-make/crate-name-priority/Makefile
 run-make/cross-lang-lto-clang/Makefile
 run-make/cross-lang-lto-pgo-smoketest/Makefile
 run-make/cross-lang-lto-upstream-rlibs/Makefile
 run-make/cross-lang-lto/Makefile
-run-make/debug-assertions/Makefile
-run-make/debugger-visualizer-dep-info/Makefile
 run-make/dep-info-doesnt-run-much/Makefile
 run-make/dep-info-spaces/Makefile
 run-make/dep-info/Makefile
 run-make/dump-ice-to-disk/Makefile
 run-make/dump-mono-stats/Makefile
-run-make/dylib-chain/Makefile
-run-make/emit-path-unhashed/Makefile
-run-make/emit-shared-files/Makefile
-run-make/emit-stack-sizes/Makefile
 run-make/emit-to-stdout/Makefile
 run-make/env-dep-info/Makefile
-run-make/error-writing-dependencies/Makefile
 run-make/export-executable-symbols/Makefile
 run-make/extern-diff-internal-name/Makefile
 run-make/extern-flag-disambiguates/Makefile
-run-make/extern-flag-pathless/Makefile
-run-make/extern-flag-rename-transitive/Makefile
 run-make/extern-fn-explicit-align/Makefile
 run-make/extern-fn-generic/Makefile
 run-make/extern-fn-mangle/Makefile
@@ -50,27 +37,18 @@ run-make/extern-fn-with-packed-struct/Makefile
 run-make/extern-fn-with-union/Makefile
 run-make/extern-multiple-copies/Makefile
 run-make/extern-multiple-copies2/Makefile
-run-make/extern-overrides-distribution/Makefile
 run-make/extra-filename-with-temp-outputs/Makefile
 run-make/fmt-write-bloat/Makefile
-run-make/forced-unwind-terminate-pof/Makefile
 run-make/foreign-double-unwind/Makefile
 run-make/foreign-exceptions/Makefile
 run-make/foreign-rust-exceptions/Makefile
-run-make/include_bytes_deps/Makefile
 run-make/incr-add-rust-src-component/Makefile
 run-make/incr-foreign-head-span/Makefile
-run-make/inline-always-many-cgu/Makefile
 run-make/interdependent-c-libraries/Makefile
-run-make/intrinsic-unreachable/Makefile
-run-make/invalid-library/Makefile
-run-make/invalid-so/Makefile
 run-make/issue-107094/Makefile
-run-make/issue-109934-lto-debuginfo/Makefile
 run-make/issue-14698/Makefile
 run-make/issue-15460/Makefile
 run-make/issue-18943/Makefile
-run-make/issue-20626/Makefile
 run-make/issue-22131/Makefile
 run-make/issue-25581/Makefile
 run-make/issue-26006/Makefile
@@ -78,14 +56,9 @@ run-make/issue-28595/Makefile
 run-make/issue-33329/Makefile
 run-make/issue-35164/Makefile
 run-make/issue-36710/Makefile
-run-make/issue-37839/Makefile
-run-make/issue-40535/Makefile
-run-make/issue-47384/Makefile
 run-make/issue-47551/Makefile
-run-make/issue-68794-textrel-on-minimal-lib/Makefile
 run-make/issue-69368/Makefile
 run-make/issue-83045/Makefile
-run-make/issue-83112-incr-test-moved-file/Makefile
 run-make/issue-84395-lto-embed-bitcode/Makefile
 run-make/issue-85019-moved-src-dir/Makefile
 run-make/issue-85401-static-mir/Makefile
@@ -95,128 +68,73 @@ run-make/jobserver-error/Makefile
 run-make/libs-through-symlinks/Makefile
 run-make/libtest-json/Makefile
 run-make/libtest-junit/Makefile
-run-make/libtest-padding/Makefile
 run-make/libtest-thread-limit/Makefile
-run-make/link-args-order/Makefile
 run-make/link-cfg/Makefile
 run-make/link-framework/Makefile
 run-make/link-path-order/Makefile
 run-make/linkage-attr-on-static/Makefile
-run-make/llvm-ident/Makefile
 run-make/long-linker-command-lines-cmd-exe/Makefile
 run-make/long-linker-command-lines/Makefile
 run-make/longjmp-across-rust/Makefile
-run-make/ls-metadata/Makefile
-run-make/lto-dylib-dep/Makefile
-run-make/lto-empty/Makefile
 run-make/lto-linkage-used-attr/Makefile
 run-make/lto-no-link-whole-rlib/Makefile
-run-make/lto-readonly-lib/Makefile
 run-make/lto-smoke-c/Makefile
 run-make/macos-deployment-target/Makefile
 run-make/macos-fat-archive/Makefile
 run-make/manual-link/Makefile
-run-make/many-crates-but-no-match/Makefile
-run-make/metadata-dep-info/Makefile
-run-make/metadata-flag-frobs-symbols/Makefile
 run-make/min-global-align/Makefile
-run-make/mingw-export-call-convention/Makefile
-run-make/mismatching-target-triples/Makefile
 run-make/missing-crate-dependency/Makefile
 run-make/mixing-libs/Makefile
-run-make/msvc-opt-minsize/Makefile
 run-make/native-link-modifier-bundle/Makefile
 run-make/native-link-modifier-whole-archive/Makefile
 run-make/no-alloc-shim/Makefile
 run-make/no-builtins-attribute/Makefile
 run-make/no-duplicate-libs/Makefile
 run-make/obey-crate-type-flag/Makefile
-run-make/optimization-remarks-dir-pgo/Makefile
-run-make/optimization-remarks-dir/Makefile
-run-make/output-type-permutations/Makefile
-run-make/override-aliased-flags/Makefile
-run-make/overwrite-input/Makefile
 run-make/panic-abort-eh_frame/Makefile
-run-make/pass-linker-flags-flavor/Makefile
-run-make/pass-linker-flags-from-dep/Makefile
-run-make/pass-linker-flags/Makefile
 run-make/pass-non-c-like-enum-to-c/Makefile
-run-make/pdb-alt-path/Makefile
 run-make/pdb-buildinfo-cl-cmd/Makefile
 run-make/pgo-gen-lto/Makefile
 run-make/pgo-gen-no-imp-symbols/Makefile
-run-make/pgo-gen/Makefile
 run-make/pgo-indirect-call-promotion/Makefile
-run-make/pgo-use/Makefile
 run-make/pointer-auth-link-with-c/Makefile
-run-make/pretty-print-to-file/Makefile
-run-make/pretty-print-with-dep-file/Makefile
 run-make/print-calling-conventions/Makefile
 run-make/print-target-list/Makefile
-run-make/profile/Makefile
 run-make/prune-link-args/Makefile
 run-make/raw-dylib-alt-calling-convention/Makefile
 run-make/raw-dylib-c/Makefile
-run-make/raw-dylib-cross-compilation/Makefile
 run-make/raw-dylib-custom-dlltool/Makefile
 run-make/raw-dylib-import-name-type/Makefile
 run-make/raw-dylib-inline-cross-dylib/Makefile
 run-make/raw-dylib-link-ordinal/Makefile
 run-make/raw-dylib-stdcall-ordinal/Makefile
 run-make/redundant-libs/Makefile
-run-make/relocation-model/Makefile
-run-make/relro-levels/Makefile
 run-make/remap-path-prefix-dwarf/Makefile
-run-make/remap-path-prefix/Makefile
 run-make/reproducible-build-2/Makefile
 run-make/reproducible-build/Makefile
 run-make/return-non-c-like-enum-from-c/Makefile
-run-make/return-non-c-like-enum/Makefile
-run-make/rlib-chain/Makefile
 run-make/rlib-format-packed-bundled-libs-2/Makefile
 run-make/rlib-format-packed-bundled-libs-3/Makefile
 run-make/rlib-format-packed-bundled-libs/Makefile
-run-make/rmeta-preferred/Makefile
 run-make/rustc-macro-dep-files/Makefile
-run-make/rustdoc-io-error/Makefile
 run-make/sanitizer-cdylib-link/Makefile
 run-make/sanitizer-dylib-link/Makefile
 run-make/sanitizer-staticlib-link/Makefile
-run-make/sepcomp-cci-copies/Makefile
-run-make/sepcomp-inlining/Makefile
-run-make/sepcomp-separate/Makefile
 run-make/share-generics-dylib/Makefile
-run-make/silly-file-names/Makefile
 run-make/simd-ffi/Makefile
 run-make/split-debuginfo/Makefile
 run-make/stable-symbol-names/Makefile
 run-make/static-dylib-by-default/Makefile
 run-make/static-extern-type/Makefile
-run-make/static-pie/Makefile
 run-make/staticlib-blank-lib/Makefile
 run-make/staticlib-dylib-linkage/Makefile
 run-make/std-core-cycle/Makefile
 run-make/symbol-mangling-hashed/Makefile
 run-make/symbol-visibility/Makefile
-run-make/symbols-include-type-name/Makefile
 run-make/sysroot-crates-are-unstable/Makefile
-run-make/target-cpu-native/Makefile
-run-make/target-specs/Makefile
-run-make/target-without-atomic-cas/Makefile
 run-make/test-benches/Makefile
-run-make/test-harness/Makefile
 run-make/thumb-none-cortex-m/Makefile
 run-make/thumb-none-qemu/Makefile
-run-make/track-path-dep-info/Makefile
-run-make/track-pgo-dep-info/Makefile
 run-make/translation/Makefile
-run-make/type-mismatch-same-crate-name/Makefile
-run-make/unknown-mod-stdin/Makefile
 run-make/unstable-flag-required/Makefile
-run-make/use-suggestions-rust-2018/Makefile
-run-make/used-cdylib-macos/Makefile
-run-make/volatile-intrinsics/Makefile
-run-make/wasm-exceptions-nostd/Makefile
-run-make/wasm-override-linker/Makefile
-run-make/weird-output-filenames/Makefile
 run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 7337c9843c7..82fa43f581f 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -1,7 +1,9 @@
 //! Checks the licenses of third-party dependencies.
 
+use build_helper::ci::CiEnv;
 use cargo_metadata::{Metadata, Package, PackageId};
 use std::collections::HashSet;
+use std::fs::read_dir;
 use std::path::Path;
 
 /// These are licenses that are allowed for all crates, including the runtime,
@@ -333,6 +335,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "proc-macro2",
     "psm",
     "pulldown-cmark",
+    "pulldown-cmark-escape",
     "punycode",
     "quote",
     "r-efi",
@@ -514,7 +517,19 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
 pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
     let mut checked_runtime_licenses = false;
 
+    let submodules = build_helper::util::parse_gitmodules(root);
     for &(workspace, exceptions, permitted_deps) in WORKSPACES {
+        // Skip if it's a submodule, not in a CI environment, and not initialized.
+        //
+        // This prevents enforcing developers to fetch submodules for tidy.
+        if submodules.contains(&workspace.into())
+            && !CiEnv::is_ci()
+            // If the directory is empty, we can consider it as an uninitialized submodule.
+            && read_dir(root.join(workspace)).unwrap().next().is_none()
+        {
+            continue;
+        }
+
         if !root.join(workspace).join("Cargo.lock").exists() {
             tidy_error!(bad, "the `{workspace}` workspace doesn't have a Cargo.lock");
             continue;
diff --git a/src/tools/tidy/src/ext_tool_checks.rs b/src/tools/tidy/src/ext_tool_checks.rs
index 995ad58cb62..8ce44115ef3 100644
--- a/src/tools/tidy/src/ext_tool_checks.rs
+++ b/src/tools/tidy/src/ext_tool_checks.rs
@@ -73,6 +73,8 @@ fn check_impl(
     let python_fmt = lint_args.contains(&"py:fmt") || python_all;
     let shell_all = lint_args.contains(&"shell");
     let shell_lint = lint_args.contains(&"shell:lint") || shell_all;
+    let cpp_all = lint_args.contains(&"cpp");
+    let cpp_fmt = lint_args.contains(&"cpp:fmt") || cpp_all;
 
     let mut py_path = None;
 
@@ -81,7 +83,7 @@ fn check_impl(
         .map(OsStr::new)
         .partition(|arg| arg.to_str().is_some_and(|s| s.starts_with('-')));
 
-    if python_lint || python_fmt {
+    if python_lint || python_fmt || cpp_fmt {
         let venv_path = outdir.join("venv");
         let mut reqs_path = root_path.to_owned();
         reqs_path.extend(PIP_REQ_PATH);
@@ -110,13 +112,14 @@ fn check_impl(
         }
 
         let mut args = merge_args(&cfg_args_ruff, &file_args_ruff);
-        let res = py_runner(py_path.as_ref().unwrap(), "ruff", &args);
+        args.insert(0, "check".as_ref());
+        let res = py_runner(py_path.as_ref().unwrap(), true, None, "ruff", &args);
 
         if res.is_err() && show_diff {
             eprintln!("\npython linting failed! Printing diff suggestions:");
 
-            args.insert(0, "--diff".as_ref());
-            let _ = py_runner(py_path.as_ref().unwrap(), "ruff", &args);
+            args.insert(1, "--diff".as_ref());
+            let _ = py_runner(py_path.as_ref().unwrap(), true, None, "ruff", &args);
         }
         // Rethrow error
         let _ = res?;
@@ -143,13 +146,84 @@ fn check_impl(
         }
 
         let mut args = merge_args(&cfg_args_black, &file_args_black);
-        let res = py_runner(py_path.as_ref().unwrap(), "black", &args);
+        let res = py_runner(py_path.as_ref().unwrap(), true, None, "black", &args);
 
         if res.is_err() && show_diff {
             eprintln!("\npython formatting does not match! Printing diff:");
 
             args.insert(0, "--diff".as_ref());
-            let _ = py_runner(py_path.as_ref().unwrap(), "black", &args);
+            let _ = py_runner(py_path.as_ref().unwrap(), true, None, "black", &args);
+        }
+        // Rethrow error
+        let _ = res?;
+    }
+
+    if cpp_fmt {
+        let mut cfg_args_clang_format = cfg_args.clone();
+        let mut file_args_clang_format = file_args.clone();
+        let config_path = root_path.join(".clang-format");
+        let config_file_arg = format!("file:{}", config_path.display());
+        cfg_args_clang_format.extend(&["--style".as_ref(), config_file_arg.as_ref()]);
+        if bless {
+            eprintln!("formatting C++ files");
+            cfg_args_clang_format.push("-i".as_ref());
+        } else {
+            eprintln!("checking C++ file formatting");
+            cfg_args_clang_format.extend(&["--dry-run".as_ref(), "--Werror".as_ref()]);
+        }
+        let files;
+        if file_args_clang_format.is_empty() {
+            let llvm_wrapper = root_path.join("compiler/rustc_llvm/llvm-wrapper");
+            files = find_with_extension(
+                root_path,
+                Some(llvm_wrapper.as_path()),
+                &[OsStr::new("h"), OsStr::new("cpp")],
+            )?;
+            file_args_clang_format.extend(files.iter().map(|p| p.as_os_str()));
+        }
+        let args = merge_args(&cfg_args_clang_format, &file_args_clang_format);
+        let res = py_runner(py_path.as_ref().unwrap(), false, None, "clang-format", &args);
+
+        if res.is_err() && show_diff {
+            eprintln!("\nclang-format linting failed! Printing diff suggestions:");
+
+            let mut cfg_args_clang_format_diff = cfg_args.clone();
+            cfg_args_clang_format_diff.extend(&["--style".as_ref(), config_file_arg.as_ref()]);
+            for file in file_args_clang_format {
+                let mut formatted = String::new();
+                let mut diff_args = cfg_args_clang_format_diff.clone();
+                diff_args.push(file);
+                let _ = py_runner(
+                    py_path.as_ref().unwrap(),
+                    false,
+                    Some(&mut formatted),
+                    "clang-format",
+                    &diff_args,
+                );
+                if formatted.is_empty() {
+                    eprintln!(
+                        "failed to obtain the formatted content for '{}'",
+                        file.to_string_lossy()
+                    );
+                    continue;
+                }
+                let actual = std::fs::read_to_string(file).unwrap_or_else(|e| {
+                    panic!(
+                        "failed to read the C++ file at '{}' due to '{e}'",
+                        file.to_string_lossy()
+                    )
+                });
+                if formatted != actual {
+                    let diff = similar::TextDiff::from_lines(&actual, &formatted);
+                    eprintln!(
+                        "{}",
+                        diff.unified_diff().context_radius(4).header(
+                            &format!("{} (actual)", file.to_string_lossy()),
+                            &format!("{} (formatted)", file.to_string_lossy())
+                        )
+                    );
+                }
+            }
         }
         // Rethrow error
         let _ = res?;
@@ -161,7 +235,7 @@ fn check_impl(
         let mut file_args_shc = file_args.clone();
         let files;
         if file_args_shc.is_empty() {
-            files = find_with_extension(root_path, "sh")?;
+            files = find_with_extension(root_path, None, &[OsStr::new("sh")])?;
             file_args_shc.extend(files.iter().map(|p| p.as_os_str()));
         }
 
@@ -180,8 +254,31 @@ fn merge_args<'a>(cfg_args: &[&'a OsStr], file_args: &[&'a OsStr]) -> Vec<&'a Os
 }
 
 /// Run a python command with given arguments. `py_path` should be a virtualenv.
-fn py_runner(py_path: &Path, bin: &'static str, args: &[&OsStr]) -> Result<(), Error> {
-    let status = Command::new(py_path).arg("-m").arg(bin).args(args).status()?;
+///
+/// Captures `stdout` to a string if provided, otherwise prints the output.
+fn py_runner(
+    py_path: &Path,
+    as_module: bool,
+    stdout: Option<&mut String>,
+    bin: &'static str,
+    args: &[&OsStr],
+) -> Result<(), Error> {
+    let mut cmd = Command::new(py_path);
+    if as_module {
+        cmd.arg("-m").arg(bin).args(args);
+    } else {
+        let bin_path = py_path.with_file_name(bin);
+        cmd.arg(bin_path).args(args);
+    }
+    let status = if let Some(stdout) = stdout {
+        let output = cmd.output()?;
+        if let Ok(s) = std::str::from_utf8(&output.stdout) {
+            stdout.push_str(s);
+        }
+        output.status
+    } else {
+        cmd.status()?
+    };
     if status.success() { Ok(()) } else { Err(Error::FailedCheck(bin)) }
 }
 
@@ -267,11 +364,10 @@ fn create_venv_at_path(path: &Path) -> Result<(), Error> {
 
     let stderr = String::from_utf8_lossy(&out.stderr);
     let err = if stderr.contains("No module named virtualenv") {
-        Error::Generic(
+        Error::Generic(format!(
             "virtualenv not found: you may need to install it \
-                               (`python3 -m pip install venv`)"
-                .to_owned(),
-        )
+                               (`{sys_py} -m pip install virtualenv`)"
+        ))
     } else {
         Error::Generic(format!(
             "failed to create venv at '{}' using {sys_py}: {stderr}",
@@ -356,7 +452,11 @@ fn shellcheck_runner(args: &[&OsStr]) -> Result<(), Error> {
 }
 
 /// Check git for tracked files matching an extension
-fn find_with_extension(root_path: &Path, extension: &str) -> Result<Vec<PathBuf>, Error> {
+fn find_with_extension(
+    root_path: &Path,
+    find_dir: Option<&Path>,
+    extensions: &[&OsStr],
+) -> Result<Vec<PathBuf>, Error> {
     // Untracked files show up for short status and are indicated with a leading `?`
     // -C changes git to be as if run from that directory
     let stat_output =
@@ -367,15 +467,25 @@ fn find_with_extension(root_path: &Path, extension: &str) -> Result<Vec<PathBuf>
     }
 
     let mut output = Vec::new();
-    let binding = Command::new("git").arg("-C").arg(root_path).args(["ls-files"]).output()?;
+    let binding = {
+        let mut command = Command::new("git");
+        command.arg("-C").arg(root_path).args(["ls-files"]);
+        if let Some(find_dir) = find_dir {
+            command.arg(find_dir);
+        }
+        command.output()?
+    };
     let tracked = String::from_utf8_lossy(&binding.stdout);
 
     for line in tracked.lines() {
         let line = line.trim();
         let path = Path::new(line);
 
-        if path.extension() == Some(OsStr::new(extension)) {
-            output.push(path.to_owned());
+        let Some(ref extension) = path.extension() else {
+            continue;
+        };
+        if extensions.contains(extension) {
+            output.push(root_path.join(path));
         }
     }
 
diff --git a/src/tools/tidy/src/extdeps.rs b/src/tools/tidy/src/extdeps.rs
index 2118de5f204..8bb80f11711 100644
--- a/src/tools/tidy/src/extdeps.rs
+++ b/src/tools/tidy/src/extdeps.rs
@@ -1,6 +1,7 @@
 //! Check for external package sources. Allow only vendorable packages.
 
-use std::fs;
+use build_helper::ci::CiEnv;
+use std::fs::{self, read_dir};
 use std::path::Path;
 
 /// List of allowed sources for packages.
@@ -13,7 +14,19 @@ const ALLOWED_SOURCES: &[&str] = &[
 /// Checks for external package sources. `root` is the path to the directory that contains the
 /// workspace `Cargo.toml`.
 pub fn check(root: &Path, bad: &mut bool) {
+    let submodules = build_helper::util::parse_gitmodules(root);
     for &(workspace, _, _) in crate::deps::WORKSPACES {
+        // Skip if it's a submodule, not in a CI environment, and not initialized.
+        //
+        // This prevents enforcing developers to fetch submodules for tidy.
+        if submodules.contains(&workspace.into())
+            && !CiEnv::is_ci()
+            // If the directory is empty, we can consider it as an uninitialized submodule.
+            && read_dir(root.join(workspace)).unwrap().next().is_none()
+        {
+            continue;
+        }
+
         // FIXME check other workspaces too
         // `Cargo.lock` of rust.
         let path = root.join(workspace).join("Cargo.lock");
diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index 3e84bf3c34b..e8dff2dc261 100644
--- a/src/tools/tidy/src/features.rs
+++ b/src/tools/tidy/src/features.rs
@@ -112,7 +112,7 @@ pub fn check(
             let file = entry.path();
             let filename = file.file_name().unwrap().to_string_lossy();
             let filen_underscore = filename.replace('-', "_").replace(".rs", "");
-            let filename_is_gate_test = test_filen_gate(&filen_underscore, &mut features);
+            let filename_gate = test_filen_gate(&filen_underscore, &mut features);
 
             for (i, line) in contents.lines().enumerate() {
                 let mut err = |msg: &str| {
@@ -128,7 +128,7 @@ pub fn check(
                 };
                 match features.get_mut(feature_name) {
                     Some(f) => {
-                        if filename_is_gate_test {
+                        if filename_gate == Some(feature_name) {
                             err(&format!(
                                 "The file is already marked as gate test \
                                       through its name, no need for a \
@@ -259,18 +259,18 @@ fn find_attr_val<'a>(line: &'a str, attr: &str) -> Option<&'a str> {
     r.captures(line).and_then(|c| c.get(1)).map(|m| m.as_str())
 }
 
-fn test_filen_gate(filen_underscore: &str, features: &mut Features) -> bool {
+fn test_filen_gate<'f>(filen_underscore: &'f str, features: &mut Features) -> Option<&'f str> {
     let prefix = "feature_gate_";
-    if filen_underscore.starts_with(prefix) {
+    if let Some(suffix) = filen_underscore.strip_prefix(prefix) {
         for (n, f) in features.iter_mut() {
             // Equivalent to filen_underscore == format!("feature_gate_{n}")
-            if &filen_underscore[prefix.len()..] == n {
+            if suffix == n {
                 f.has_gate_test = true;
-                return true;
+                return Some(suffix);
             }
         }
     }
-    false
+    None
 }
 
 pub fn collect_lang_features(base_compiler_path: &Path, bad: &mut bool) -> Features {
diff --git a/src/tools/tidy/src/fluent_period.rs b/src/tools/tidy/src/fluent_period.rs
new file mode 100644
index 00000000000..3a1fb6daf48
--- /dev/null
+++ b/src/tools/tidy/src/fluent_period.rs
@@ -0,0 +1,84 @@
+//! Checks that no Fluent messages or attributes end in periods (except ellipses)
+
+use fluent_syntax::ast::{Entry, PatternElement};
+
+use crate::walk::{filter_dirs, walk};
+use std::path::Path;
+
+fn filter_fluent(path: &Path) -> bool {
+    if let Some(ext) = path.extension() { ext.to_str() != Some("ftl") } else { true }
+}
+
+/// Messages allowed to have `.` at their end.
+///
+/// These should probably be reworked eventually.
+const ALLOWLIST: &[&str] = &[
+    "const_eval_long_running",
+    "const_eval_validation_failure_note",
+    "driver_impl_ice",
+    "incremental_corrupt_file",
+    "mir_build_pointer_pattern",
+];
+
+fn check_period(filename: &str, contents: &str, bad: &mut bool) {
+    if filename.contains("codegen") {
+        // FIXME: Too many codegen messages have periods right now...
+        return;
+    }
+
+    let (Ok(parse) | Err((parse, _))) = fluent_syntax::parser::parse(contents);
+    for entry in &parse.body {
+        if let Entry::Message(m) = entry {
+            if ALLOWLIST.contains(&m.id.name) {
+                continue;
+            }
+
+            if let Some(pat) = &m.value {
+                if let Some(PatternElement::TextElement { value }) = pat.elements.last() {
+                    // We don't care about ellipses.
+                    if value.ends_with(".") && !value.ends_with("...") {
+                        let ll = find_line(contents, *value);
+                        let name = m.id.name;
+                        tidy_error!(bad, "{filename}:{ll}: message `{name}` ends in a period");
+                    }
+                }
+            }
+
+            for attr in &m.attributes {
+                // Teach notes usually have long messages.
+                if attr.id.name == "teach_note" {
+                    continue;
+                }
+
+                if let Some(PatternElement::TextElement { value }) = attr.value.elements.last() {
+                    if value.ends_with(".") && !value.ends_with("...") {
+                        let ll = find_line(contents, *value);
+                        let name = attr.id.name;
+                        tidy_error!(bad, "{filename}:{ll}: attr `{name}` ends in a period");
+                    }
+                }
+            }
+        }
+    }
+}
+
+/// Evil cursed bad hack. Requires that `value` be a substr (in memory) of `contents`.
+fn find_line(haystack: &str, needle: &str) -> usize {
+    for (ll, line) in haystack.lines().enumerate() {
+        if line.as_ptr() > needle.as_ptr() {
+            return ll;
+        }
+    }
+
+    1
+}
+
+pub fn check(path: &Path, bad: &mut bool) {
+    walk(
+        path,
+        |path, is_dir| filter_dirs(path) || (!is_dir && filter_fluent(path)),
+        &mut |ent, contents| {
+            check_period(ent.path().to_str().unwrap(), contents, bad);
+        },
+    );
+}
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index ae9d2b8b8dc..ecd32727fa0 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -72,6 +72,7 @@ pub mod ext_tool_checks;
 pub mod extdeps;
 pub mod features;
 pub mod fluent_alphabetical;
+pub mod fluent_period;
 mod fluent_used;
 pub(crate) mod iter_header;
 pub mod known_bug;
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index 1d2b2e4d034..ec6fc1f07f1 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -115,6 +115,7 @@ fn main() {
         // Checks that only make sense for the compiler.
         check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], verbose);
         check!(fluent_alphabetical, &compiler_path, bless);
+        check!(fluent_period, &compiler_path);
         check!(target_policy, &root_path);
 
         // Checks that only make sense for the std libs.
diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs
index 7e5656926ab..2f8abc77566 100644
--- a/src/tools/tidy/src/pal.rs
+++ b/src/tools/tidy/src/pal.rs
@@ -45,6 +45,8 @@ const EXCEPTION_PATHS: &[&str] = &[
     // pointer regardless of the target architecture. As a result,
     // we must use `#[cfg(windows)]` to conditionally compile the
     // correct `VaList` structure for windows.
+    "library/core/src/ffi/va_list.rs",
+    // We placed a linkage against Windows libraries here
     "library/core/src/ffi/mod.rs",
     "library/std/src/sys", // Platform-specific code for std lives here.
     "library/std/src/os",  // Platform-specific public interfaces
diff --git a/src/tools/tidy/src/run_make_tests.rs b/src/tools/tidy/src/run_make_tests.rs
index 2d9f8448a35..8d176787837 100644
--- a/src/tools/tidy/src/run_make_tests.rs
+++ b/src/tools/tidy/src/run_make_tests.rs
@@ -95,7 +95,7 @@ pub fn check(tests_path: &Path, src_path: &Path, bless: bool, bad: &mut bool) {
             tidy_error!(
                 bad,
                 "Makefile `{}` no longer exists and should be removed from the exclusions in \
-                `src/tools/tidy/src/allowed_run_make_makefiles.txt`, you can run --bless to update \
+                `src/tools/tidy/src/allowed_run_make_makefiles.txt`, you can run `x test tidy --bless` to update \
                 the allow list",
                 p.display()
             );
diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs
index 7bcb85335e0..8e693c35adc 100644
--- a/src/tools/tidy/src/style.rs
+++ b/src/tools/tidy/src/style.rs
@@ -110,6 +110,7 @@ const ROOT_PROBLEMATIC_CONSTS: &[u32] = &[
     173390526, 721077,
 ];
 
+// Returns all permutations of problematic consts, over 2000 elements.
 fn generate_problematic_strings(
     consts: &[u32],
     letter_digit: &FxHashMap<char, char>,
@@ -186,6 +187,11 @@ fn should_ignore(line: &str) -> bool {
     // - `//@[rev] normalize-stderr-test`
         || static_regex!("\\s*//@(\\[.*\\]) (compile-flags|normalize-stderr-test|error-pattern).*")
             .is_match(line)
+        // Matching for rustdoc tests commands.
+        // It allows to prevent them emitting warnings like `line longer than 100 chars`.
+        || static_regex!(
+            "\\s*//@ \\!?(count|files|has|has-dir|hasraw|matches|matchesraw|snapshot)\\s.*"
+        ).is_match(line)
 }
 
 /// Returns `true` if `line` is allowed to be longer than the normal limit.
@@ -314,6 +320,8 @@ pub fn check(path: &Path, bad: &mut bool) {
         ROOT_PROBLEMATIC_CONSTS,
         &[('A', '4'), ('B', '8'), ('E', '3')].iter().cloned().collect(),
     );
+    // This creates a RegexSet as regex contains performance optimizations to be able to deal with these over
+    // 2000 needles efficiently. This runs over the entire source code, so performance matters.
     let problematic_regex = RegexSet::new(problematic_consts_strings.as_slice()).unwrap();
 
     walk(path, skip, &mut |entry, contents| {
diff --git a/src/tools/tidy/src/target_policy.rs b/src/tools/tidy/src/target_policy.rs
index 06210c8cdb2..cb9a0c1c7f4 100644
--- a/src/tools/tidy/src/target_policy.rs
+++ b/src/tools/tidy/src/target_policy.rs
@@ -14,8 +14,11 @@ const EXCEPTIONS: &[&str] = &[
     "csky_unknown_linux_gnuabiv2hf",
     // FIXME: disabled since it requires a custom LLVM until the upstream LLVM adds support for the target (https://github.com/espressif/llvm-project/issues/4)
     "xtensa_esp32_none_elf",
+    "xtensa_esp32_espidf",
     "xtensa_esp32s2_none_elf",
+    "xtensa_esp32s2_espidf",
     "xtensa_esp32s3_none_elf",
+    "xtensa_esp32s3_espidf",
 ];
 
 pub fn check(root_path: &Path, bad: &mut bool) {
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index f2eeda339d8..5e6992038e3 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -1,6 +1,7 @@
 //! Tidy check to ensure below in UI test directories:
 //! - the number of entries in each directory must be less than `ENTRY_LIMIT`
 //! - there are no stray `.stderr` files
+
 use ignore::Walk;
 use std::collections::{BTreeSet, HashMap};
 use std::ffi::OsStr;
@@ -12,7 +13,7 @@ use std::path::{Path, PathBuf};
 // should all be 1000 or lower. Limits significantly smaller than 1000 are also
 // desirable, because large numbers of files are unwieldy in general. See issue
 // #73494.
-const ENTRY_LIMIT: u32 = 900;
+const ENTRY_LIMIT: u32 = 901;
 // FIXME: The following limits should be reduced eventually.
 
 const ISSUES_ENTRY_LIMIT: u32 = 1672;