about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-08-13 15:01:50 +0000
committerbors <bors@rust-lang.org>2024-08-13 15:01:50 +0000
commitf96e296927cc0c6e9dd611edb943f6349001eca5 (patch)
tree76c5e72c0570998ece04f11ac90e09b5d2613abc /src
parent00423bb1d85f3513e534abdb26f54a6966e88d47 (diff)
parent28af7e09581c3b39cdbf2850df2f157690ab7e56 (diff)
downloadrust-f96e296927cc0c6e9dd611edb943f6349001eca5.tar.gz
rust-f96e296927cc0c6e9dd611edb943f6349001eca5.zip
Auto merge of #17880 - lnicola:sync-from-rust, r=lnicola
minor: sync from downstream
Diffstat (limited to 'src')
-rw-r--r--src/bootstrap/Cargo.lock111
-rw-r--r--src/bootstrap/Cargo.toml2
-rw-r--r--src/bootstrap/download-ci-llvm-stamp2
-rw-r--r--src/bootstrap/src/bin/main.rs25
-rw-r--r--src/bootstrap/src/bin/rustc.rs32
-rw-r--r--src/bootstrap/src/core/build_steps/check.rs65
-rw-r--r--src/bootstrap/src/core/build_steps/clean.rs8
-rw-r--r--src/bootstrap/src/core/build_steps/clippy.rs51
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs130
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs95
-rw-r--r--src/bootstrap/src/core/build_steps/doc.rs167
-rw-r--r--src/bootstrap/src/core/build_steps/format.rs14
-rw-r--r--src/bootstrap/src/core/build_steps/install.rs3
-rw-r--r--src/bootstrap/src/core/build_steps/llvm.rs38
-rw-r--r--src/bootstrap/src/core/build_steps/run.rs8
-rw-r--r--src/bootstrap/src/core/build_steps/setup.rs15
-rw-r--r--src/bootstrap/src/core/build_steps/setup/tests.rs3
-rw-r--r--src/bootstrap/src/core/build_steps/suggest.rs3
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs129
-rw-r--r--src/bootstrap/src/core/build_steps/tool.rs39
-rw-r--r--src/bootstrap/src/core/build_steps/toolstate.rs13
-rw-r--r--src/bootstrap/src/core/build_steps/vendor.rs9
-rw-r--r--src/bootstrap/src/core/builder.rs150
-rw-r--r--src/bootstrap/src/core/builder/tests.rs33
-rw-r--r--src/bootstrap/src/core/config/config.rs89
-rw-r--r--src/bootstrap/src/core/config/flags.rs37
-rw-r--r--src/bootstrap/src/core/config/mod.rs2
-rw-r--r--src/bootstrap/src/core/config/tests.rs39
-rw-r--r--src/bootstrap/src/core/download.rs27
-rw-r--r--src/bootstrap/src/core/metadata.rs7
-rw-r--r--src/bootstrap/src/core/sanity.rs22
-rw-r--r--src/bootstrap/src/lib.rs141
-rw-r--r--src/bootstrap/src/utils/cache.rs3
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs10
-rw-r--r--src/bootstrap/src/utils/channel.rs3
-rw-r--r--src/bootstrap/src/utils/exec.rs12
-rw-r--r--src/bootstrap/src/utils/helpers.rs19
-rw-r--r--src/bootstrap/src/utils/helpers/tests.rs23
-rw-r--r--src/bootstrap/src/utils/job.rs33
-rw-r--r--src/bootstrap/src/utils/metrics.rs33
-rw-r--r--src/bootstrap/src/utils/render_tests.rs6
-rw-r--r--src/bootstrap/src/utils/tarball.rs10
-rw-r--r--src/ci/docker/host-x86_64/dist-various-2/Dockerfile14
-rw-r--r--src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile5
-rw-r--r--src/ci/docker/host-x86_64/test-various/uefi_qemu_test/src/main.rs1
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile2
-rwxr-xr-xsrc/ci/docker/scripts/fuchsia-test-runner.py13
-rwxr-xr-xsrc/ci/docker/scripts/rfl-build.sh8
-rwxr-xr-xsrc/ci/docker/scripts/x86_64-gnu-llvm.sh6
-rwxr-xr-xsrc/ci/docker/scripts/zstd.sh29
m---------src/doc/reference0
-rw-r--r--src/doc/rustc/src/SUMMARY.md3
-rw-r--r--src/doc/rustc/src/command-line-arguments.md4
-rw-r--r--src/doc/rustc/src/platform-support.md20
-rw-r--r--src/doc/rustc/src/platform-support/apple-darwin.md3
-rw-r--r--src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-gnu.md129
-rw-r--r--src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-musl.md47
-rw-r--r--src/doc/rustc/src/platform-support/vxworks.md59
-rw-r--r--src/doc/unstable-book/src/language-features/rustc-private.md11
-rw-r--r--src/etc/completions/x.py.fish3
-rw-r--r--src/etc/completions/x.py.ps13
-rw-r--r--src/etc/completions/x.py.sh10
-rw-r--r--src/etc/completions/x.py.zsh3
-rw-r--r--src/etc/gdb_providers.py17
-rw-r--r--src/etc/lldb_providers.py8
-rw-r--r--src/etc/natvis/liballoc.natvis18
-rw-r--r--src/etc/natvis/libstd.natvis6
-rw-r--r--src/librustdoc/Cargo.toml3
-rw-r--r--src/librustdoc/clean/auto_trait.rs6
-rw-r--r--src/librustdoc/clean/blanket_impl.rs1
-rw-r--r--src/librustdoc/clean/cfg.rs4
-rw-r--r--src/librustdoc/clean/cfg/tests.rs7
-rw-r--r--src/librustdoc/clean/inline.rs40
-rw-r--r--src/librustdoc/clean/mod.rs114
-rw-r--r--src/librustdoc/clean/simplify.rs4
-rw-r--r--src/librustdoc/clean/types.rs115
-rw-r--r--src/librustdoc/clean/types/tests.rs4
-rw-r--r--src/librustdoc/clean/utils.rs33
-rw-r--r--src/librustdoc/config.rs25
-rw-r--r--src/librustdoc/core.rs34
-rw-r--r--src/librustdoc/docfs.rs4
-rw-r--r--src/librustdoc/doctest.rs26
-rw-r--r--src/librustdoc/doctest/rust.rs6
-rw-r--r--src/librustdoc/doctest/tests.rs3
-rw-r--r--src/librustdoc/externalfiles.rs10
-rw-r--r--src/librustdoc/fold.rs3
-rw-r--r--src/librustdoc/formats/cache.rs346
-rw-r--r--src/librustdoc/formats/item_type.rs7
-rw-r--r--src/librustdoc/formats/mod.rs3
-rw-r--r--src/librustdoc/html/escape.rs55
-rw-r--r--src/librustdoc/html/escape/tests.rs68
-rw-r--r--src/librustdoc/html/format.rs56
-rw-r--r--src/librustdoc/html/highlight.rs7
-rw-r--r--src/librustdoc/html/highlight/tests.rs5
-rw-r--r--src/librustdoc/html/layout.rs8
-rw-r--r--src/librustdoc/html/markdown.rs50
-rw-r--r--src/librustdoc/html/markdown/tests.rs14
-rw-r--r--src/librustdoc/html/render/context.rs13
-rw-r--r--src/librustdoc/html/render/mod.rs153
-rw-r--r--src/librustdoc/html/render/print_item.rs59
-rw-r--r--src/librustdoc/html/render/search_index.rs486
-rw-r--r--src/librustdoc/html/render/sidebar.rs33
-rw-r--r--src/librustdoc/html/render/span_map.rs6
-rw-r--r--src/librustdoc/html/render/type_layout.rs8
-rw-r--r--src/librustdoc/html/sources.rs29
-rw-r--r--src/librustdoc/html/static/css/noscript.css8
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css141
-rw-r--r--src/librustdoc/html/static/js/main.js136
-rw-r--r--src/librustdoc/html/static_files.rs3
-rw-r--r--src/librustdoc/html/templates/page.html2
-rw-r--r--src/librustdoc/html/templates/sidebar.html8
-rw-r--r--src/librustdoc/html/tests.rs3
-rw-r--r--src/librustdoc/json/conversions.rs36
-rw-r--r--src/librustdoc/json/import_finder.rs6
-rw-r--r--src/librustdoc/json/mod.rs8
-rw-r--r--src/librustdoc/lib.rs3
-rw-r--r--src/librustdoc/lint.rs4
-rw-r--r--src/librustdoc/passes/calculate_doc_coverage.rs17
-rw-r--r--src/librustdoc/passes/check_doc_test_visibility.rs9
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs24
-rw-r--r--src/librustdoc/passes/collect_trait_impls.rs10
-rw-r--r--src/librustdoc/passes/lint/bare_urls.rs12
-rw-r--r--src/librustdoc/passes/lint/check_code_block_syntax.rs8
-rw-r--r--src/librustdoc/passes/lint/html_tags.rs12
-rw-r--r--src/librustdoc/passes/lint/redundant_explicit_links.rs3
-rw-r--r--src/librustdoc/passes/lint/unescaped_backticks.rs10
-rw-r--r--src/librustdoc/passes/lint/unportable_markdown.rs11
-rw-r--r--src/librustdoc/passes/propagate_doc_cfg.rs4
-rw-r--r--src/librustdoc/passes/strip_aliased_non_local.rs3
-rw-r--r--src/librustdoc/passes/strip_hidden.rs3
-rw-r--r--src/librustdoc/passes/stripper.rs15
-rw-r--r--src/librustdoc/scrape_examples.rs32
-rw-r--r--src/librustdoc/theme.rs2
-rw-r--r--src/librustdoc/visit.rs3
-rw-r--r--src/librustdoc/visit_ast.rs7
-rw-r--r--src/librustdoc/visit_lib.rs3
m---------src/llvm-project0
-rw-r--r--src/rustdoc-json-types/lib.rs600
-rw-r--r--src/stage0870
-rw-r--r--src/tools/build-manifest/src/checksum.rs8
-rw-r--r--src/tools/build-manifest/src/main.rs9
-rw-r--r--src/tools/build-manifest/src/manifest.rs8
-rw-r--r--src/tools/build-manifest/src/versions.rs8
-rw-r--r--src/tools/build_helper/src/git.rs4
-rw-r--r--src/tools/bump-stage0/src/main.rs5
m---------src/tools/cargo0
-rw-r--r--src/tools/cargotest/main.rs3
-rw-r--r--src/tools/clippy/.cargo/config.toml7
-rw-r--r--src/tools/clippy/.github/workflows/clippy.yml13
-rw-r--r--src/tools/clippy/.github/workflows/clippy_bors.yml17
-rw-r--r--src/tools/clippy/.github/workflows/clippy_dev.yml5
-rw-r--r--src/tools/clippy/.github/workflows/lintcheck.yml4
-rw-r--r--src/tools/clippy/CHANGELOG.md2
-rw-r--r--src/tools/clippy/Cargo.toml3
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md6
-rw-r--r--src/tools/clippy/clippy_config/Cargo.toml4
-rw-r--r--src/tools/clippy/clippy_config/src/conf.rs724
-rw-r--r--src/tools/clippy/clippy_config/src/lib.rs3
-rw-r--r--src/tools/clippy/clippy_config/src/metadata.rs105
-rw-r--r--src/tools/clippy/clippy_dev/Cargo.toml3
-rw-r--r--src/tools/clippy/clippy_dev/src/fmt.rs392
-rw-r--r--src/tools/clippy/clippy_dev/src/lib.rs1
-rw-r--r--src/tools/clippy/clippy_dev/src/main.rs5
-rw-r--r--src/tools/clippy/clippy_dev/src/serve.rs15
-rw-r--r--src/tools/clippy/clippy_dev/src/update_lints.rs324
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml1
-rw-r--r--src/tools/clippy/clippy_lints/src/approx_const.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/as_conversions.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/asm_syntax.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/assertions_on_constants.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs47
-rw-r--r--src/tools/clippy/clippy_lints/src/assigning_clones.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/booleans.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs37
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/zero_ptr.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/checked_conversions.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/comparison_chain.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/create_dir.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/dbg_macro.rs108
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/default.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/default_union_representation.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/deprecated_lints.rs394
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/mod.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/drop_forget_ref.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/else_if_without_else.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/empty_drop.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/endian_bytes.rs89
-rw-r--r--src/tools/clippy/clippy_lints/src/enum_clike.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs327
-rw-r--r--src/tools/clippy/clippy_lints/src/exhaustive_items.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/float_literal.rs45
-rw-r--r--src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs36
-rw-r--r--src/tools/clippy/clippy_lints/src/format_push_string.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/from_str_radix_10.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/if_let_mutex.rs66
-rw-r--r--src/tools/clippy/clippy_lints/src/if_not_else.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs47
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_hasher.rs53
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_return.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/incompatible_msrv.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/index_refutable_slice.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/indexing_slicing.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/infinite_iter.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_impl.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/large_include_file.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/let_underscore.rs58
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.deprecated.rs78
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs82
-rw-r--r--src/tools/clippy/clippy_lints/src/literal_representation.rs77
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mod.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_clamp.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_float_methods.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_rotate.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_strip.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_ref_pats.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs39
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/mod.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/single_match.rs394
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/try_err.rs39
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs44
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/is_empty.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_skip_zero.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_clone.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs28
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/open_options.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/repeat_once.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/str_splitn.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/useless_asref.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/verbose_file_reads.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/minmax.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_assert_message.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_trait_methods.rs46
-rw-r--r--src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/module_style.rs32
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs48
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/no_effect.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/bit_mask.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/erasing_op.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/float_cmp.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/identity_op.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/integer_division.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/op_ref.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/option_if_let_else.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/partial_pub_fields.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/pub_use.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark_used.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/ranges.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_clone.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_slicing.rs68
-rw-r--r--src/tools/clippy/clippy_lints/src/ref_patterns.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/regex.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/renamed_lints.rs65
-rw-r--r--src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/semicolon_block.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs33
-rw-r--r--src/tools/clippy/clippy_lints/src/shadow.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/size_of_ref.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/std_instead_of_core.rs69
-rw-r--r--src/tools/clippy/clippy_lints/src/strings.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/swap.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/mod.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/types/borrowed_box.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/types/rc_buffer.rs62
-rw-r--r--src/tools/clippy/clippy_lints/src/types/rc_mutex.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs53
-rw-r--r--src/tools/clippy/clippy_lints/src/unicode.rs64
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_result_ok.rs59
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs85
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs117
-rw-r--r--src/tools/clippy/clippy_lints/src/vec.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/visibility.rs43
-rw-r--r--src/tools/clippy/clippy_lints/src/zero_div_zero.rs7
-rw-r--r--src/tools/clippy/clippy_utils/Cargo.toml3
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs279
-rw-r--r--src/tools/clippy/clippy_utils/src/diagnostics.rs29
-rw-r--r--src/tools/clippy/clippy_utils/src/eager_or_lazy.rs16
-rw-r--r--src/tools/clippy/clippy_utils/src/higher.rs13
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs12
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs48
-rw-r--r--src/tools/clippy/clippy_utils/src/paths.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/source.rs129
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs13
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs98
-rw-r--r--src/tools/clippy/declare_clippy_lint/Cargo.toml3
-rw-r--r--src/tools/clippy/declare_clippy_lint/src/lib.rs1
-rw-r--r--src/tools/clippy/lintcheck/Cargo.toml3
-rw-r--r--src/tools/clippy/lintcheck/src/config.rs8
-rw-r--r--src/tools/clippy/lintcheck/src/input.rs6
-rw-r--r--src/tools/clippy/lintcheck/src/main.rs28
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/rustc_tools_util/Cargo.toml3
-rw-r--r--src/tools/clippy/rustc_tools_util/src/lib.rs59
-rw-r--r--src/tools/clippy/src/driver.rs3
-rw-r--r--src/tools/clippy/src/main.rs4
-rw-r--r--src/tools/clippy/tests/check-fmt.rs1
-rw-r--r--src/tools/clippy/tests/compile-test.rs9
-rw-r--r--src/tools/clippy/tests/dogfood.rs1
-rw-r--r--src/tools/clippy/tests/integration.rs1
-rw-r--r--src/tools/clippy/tests/lint_message_convention.rs1
-rw-r--r--src/tools/clippy/tests/missing-test-files.rs1
-rw-r--r--src/tools/clippy/tests/ui-internal/default_deprecation_reason.rs30
-rw-r--r--src/tools/clippy/tests/ui-internal/default_deprecation_reason.stderr22
-rw-r--r--src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.rs20
-rw-r--r--src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.stderr74
-rw-r--r--src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr134
-rw-r--r--src/tools/clippy/tests/ui/assigning_clones.fixed68
-rw-r--r--src/tools/clippy/tests/ui/assigning_clones.rs68
-rw-r--r--src/tools/clippy/tests/ui/assigning_clones.stderr86
-rw-r--r--src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr10
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs3
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr6
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-3717.stderr11
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6254.rs3
-rw-r--r--src/tools/clippy/tests/ui/create_dir.stderr13
-rw-r--r--src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr4
-rw-r--r--src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.stderr2
-rw-r--r--src/tools/clippy/tests/ui/deprecated.rs31
-rw-r--r--src/tools/clippy/tests/ui/deprecated.stderr68
-rw-r--r--src/tools/clippy/tests/ui/deprecated_old.rs9
-rw-r--r--src/tools/clippy/tests/ui/deprecated_old.stderr23
-rw-r--r--src/tools/clippy/tests/ui/deref_by_slicing.fixed4
-rw-r--r--src/tools/clippy/tests/ui/deref_by_slicing.rs4
-rw-r--r--src/tools/clippy/tests/ui/deref_by_slicing.stderr8
-rw-r--r--src/tools/clippy/tests/ui/doc/footnote_issue_13183.rs10
-rw-r--r--src/tools/clippy/tests/ui/empty_drop.stderr7
-rw-r--r--src/tools/clippy/tests/ui/eta.fixed17
-rw-r--r--src/tools/clippy/tests/ui/eta.rs17
-rw-r--r--src/tools/clippy/tests/ui/eta.stderr74
-rw-r--r--src/tools/clippy/tests/ui/excessive_precision.stderr111
-rw-r--r--src/tools/clippy/tests/ui/explicit_counter_loop.rs13
-rw-r--r--src/tools/clippy/tests/ui/explicit_counter_loop.stderr8
-rw-r--r--src/tools/clippy/tests/ui/fn_to_numeric_cast_any.stderr118
-rw-r--r--src/tools/clippy/tests/ui/for_kv_map.fixed10
-rw-r--r--src/tools/clippy/tests/ui/for_kv_map.rs10
-rw-r--r--src/tools/clippy/tests/ui/for_kv_map.stderr13
-rw-r--r--src/tools/clippy/tests/ui/get_unwrap.stderr152
-rw-r--r--src/tools/clippy/tests/ui/if_let_mutex.rs9
-rw-r--r--src/tools/clippy/tests/ui/if_let_mutex.stderr24
-rw-r--r--src/tools/clippy/tests/ui/if_then_some_else_none.fixed119
-rw-r--r--src/tools/clippy/tests/ui/if_then_some_else_none.rs2
-rw-r--r--src/tools/clippy/tests/ui/if_then_some_else_none.stderr19
-rw-r--r--src/tools/clippy/tests/ui/implicit_hasher.fixed102
-rw-r--r--src/tools/clippy/tests/ui/implicit_hasher.rs9
-rw-r--r--src/tools/clippy/tests/ui/implicit_hasher.stderr131
-rw-r--r--src/tools/clippy/tests/ui/implicit_return.stderr104
-rw-r--r--src/tools/clippy/tests/ui/lossy_float_literal.stderr76
-rw-r--r--src/tools/clippy/tests/ui/missing_trait_methods.rs8
-rw-r--r--src/tools/clippy/tests/ui/missing_trait_methods.stderr38
-rw-r--r--src/tools/clippy/tests/ui/needless_borrows_for_generic_args.fixed8
-rw-r--r--src/tools/clippy/tests/ui/needless_borrows_for_generic_args.rs8
-rw-r--r--src/tools/clippy/tests/ui/needless_pub_self.stderr11
-rw-r--r--src/tools/clippy/tests/ui/nonminimal_bool.rs6
-rw-r--r--src/tools/clippy/tests/ui/patterns.fixed2
-rw-r--r--src/tools/clippy/tests/ui/patterns.rs2
-rw-r--r--src/tools/clippy/tests/ui/rename.fixed131
-rw-r--r--src/tools/clippy/tests/ui/rename.rs131
-rw-r--r--src/tools/clippy/tests/ui/rename.stderr158
-rw-r--r--src/tools/clippy/tests/ui/set_contains_or_insert.rs83
-rw-r--r--src/tools/clippy/tests/ui/set_contains_or_insert.stderr72
-rw-r--r--src/tools/clippy/tests/ui/single_match.fixed43
-rw-r--r--src/tools/clippy/tests/ui/single_match.rs49
-rw-r--r--src/tools/clippy/tests/ui/single_match.stderr20
-rw-r--r--src/tools/clippy/tests/ui/single_match_else.fixed2
-rw-r--r--src/tools/clippy/tests/ui/single_match_else.rs2
-rw-r--r--src/tools/clippy/tests/ui/single_match_else.stderr4
-rw-r--r--src/tools/clippy/tests/ui/std_instead_of_core.fixed17
-rw-r--r--src/tools/clippy/tests/ui/std_instead_of_core.rs17
-rw-r--r--src/tools/clippy/tests/ui/std_instead_of_core.stderr14
-rw-r--r--src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.stderr47
-rw-r--r--src/tools/clippy/tests/ui/try_err.fixed10
-rw-r--r--src/tools/clippy/tests/ui/try_err.rs10
-rw-r--r--src/tools/clippy/tests/ui/uninit_vec.rs7
-rw-r--r--src/tools/clippy/tests/ui/uninit_vec.stderr38
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr4
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_wraps.stderr8
-rw-r--r--src/tools/clippy/tests/ui/unneeded_field_pattern.rs2
-rw-r--r--src/tools/clippy/tests/ui/unused_result_ok.fixed40
-rw-r--r--src/tools/clippy/tests/ui/unused_result_ok.rs40
-rw-r--r--src/tools/clippy/tests/ui/unused_result_ok.stderr52
-rw-r--r--src/tools/clippy/tests/ui/unwrap_expect_used.rs2
-rw-r--r--src/tools/clippy/tests/ui/while_let_on_iterator.fixed9
-rw-r--r--src/tools/clippy/tests/ui/while_let_on_iterator.rs9
-rw-r--r--src/tools/clippy/tests/ui/while_let_on_iterator.stderr8
-rw-r--r--src/tools/clippy/tests/versioncheck.rs1
-rw-r--r--src/tools/clippy/tests/workspace_test/path_dep/Cargo.toml3
-rw-r--r--src/tools/clippy/util/gh-pages/index.html4
-rw-r--r--src/tools/clippy/util/gh-pages/script.js74
-rw-r--r--src/tools/collect-license-metadata/Cargo.toml2
-rw-r--r--src/tools/collect-license-metadata/src/main.rs11
-rw-r--r--src/tools/collect-license-metadata/src/path_tree.rs3
-rw-r--r--src/tools/collect-license-metadata/src/reuse.rs6
-rw-r--r--src/tools/compiletest/src/command-list.rs5
-rw-r--r--src/tools/compiletest/src/common.rs11
-rw-r--r--src/tools/compiletest/src/errors.rs4
-rw-r--r--src/tools/compiletest/src/header.rs17
-rw-r--r--src/tools/compiletest/src/header/cfg.rs3
-rw-r--r--src/tools/compiletest/src/header/tests.rs3
-rw-r--r--src/tools/compiletest/src/json.rs8
-rw-r--r--src/tools/compiletest/src/lib.rs16
-rw-r--r--src/tools/compiletest/src/main.rs7
-rw-r--r--src/tools/compiletest/src/raise_fd_limit.rs3
-rw-r--r--src/tools/compiletest/src/read2.rs9
-rw-r--r--src/tools/compiletest/src/runtest.rs160
-rw-r--r--src/tools/compiletest/src/runtest/coverage.rs2
-rw-r--r--src/tools/compiletest/src/runtest/debugger.rs8
-rw-r--r--src/tools/compiletest/src/util.rs3
-rw-r--r--src/tools/coverage-dump/src/covfun.rs8
-rw-r--r--src/tools/coverage-dump/src/parser.rs3
-rw-r--r--src/tools/coverage-dump/src/prf_names.rs8
-rw-r--r--src/tools/error_index_generator/main.rs6
-rw-r--r--src/tools/generate-copyright/Cargo.toml4
-rw-r--r--src/tools/generate-copyright/src/cargo_metadata.rs191
-rw-r--r--src/tools/generate-copyright/src/main.rs102
-rw-r--r--src/tools/generate-copyright/templates/COPYRIGHT.html54
-rw-r--r--src/tools/generate-copyright/templates/Node.html71
-rw-r--r--src/tools/generate-windows-sys/src/main.rs3
-rw-r--r--src/tools/html-checker/main.rs3
-rw-r--r--src/tools/jsondocck/src/cache.rs5
-rw-r--r--src/tools/jsondocck/src/error.rs3
-rw-r--r--src/tools/jsondocck/src/main.rs7
-rw-r--r--src/tools/jsondoclint/src/item_kind.rs5
-rw-r--r--src/tools/jsondoclint/src/validator.rs15
-rw-r--r--src/tools/jsondoclint/src/validator/tests.rs3
-rw-r--r--src/tools/linkchecker/main.rs12
-rw-r--r--src/tools/lint-docs/src/groups.rs3
-rw-r--r--src/tools/lint-docs/src/lib.rs1
-rw-r--r--src/tools/lld-wrapper/src/main.rs3
-rw-r--r--src/tools/llvm-bitcode-linker/src/bin/llvm-bitcode-linker.rs1
-rw-r--r--src/tools/llvm-bitcode-linker/src/linker.rs3
-rw-r--r--src/tools/llvm-bitcode-linker/src/opt.rs3
-rw-r--r--src/tools/miri/Cargo.lock237
-rw-r--r--src/tools/miri/Cargo.toml11
-rw-r--r--src/tools/miri/README.md16
-rw-r--r--src/tools/miri/cargo-miri/Cargo.lock153
-rw-r--r--src/tools/miri/cargo-miri/Cargo.toml2
-rw-r--r--src/tools/miri/cargo-miri/src/setup.rs5
-rwxr-xr-xsrc/tools/miri/ci/ci.sh2
-rw-r--r--src/tools/miri/miri-script/src/commands.rs5
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/alloc_addresses/mod.rs38
-rw-r--r--src/tools/miri/src/bin/miri.rs82
-rw-r--r--src/tools/miri/src/borrow_tracker/mod.rs4
-rw-r--r--src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs20
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs13
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs11
-rw-r--r--src/tools/miri/src/concurrency/data_race.rs4
-rw-r--r--src/tools/miri/src/concurrency/thread.rs8
-rw-r--r--src/tools/miri/src/concurrency/weak_memory.rs8
-rw-r--r--src/tools/miri/src/diagnostics.rs141
-rw-r--r--src/tools/miri/src/eval.rs40
-rw-r--r--src/tools/miri/src/helpers.rs71
-rw-r--r--src/tools/miri/src/intrinsics/mod.rs4
-rw-r--r--src/tools/miri/src/lib.rs3
-rw-r--r--src/tools/miri/src/machine.rs116
-rw-r--r--src/tools/miri/src/shims/backtrace.rs6
-rw-r--r--src/tools/miri/src/shims/env.rs5
-rw-r--r--src/tools/miri/src/shims/foreign_items.rs22
-rw-r--r--src/tools/miri/src/shims/panic.rs30
-rw-r--r--src/tools/miri/src/shims/time.rs16
-rw-r--r--src/tools/miri/src/shims/tls.rs8
-rw-r--r--src/tools/miri/src/shims/unix/env.rs55
-rw-r--r--src/tools/miri/src/shims/unix/fd.rs236
-rw-r--r--src/tools/miri/src/shims/unix/foreign_items.rs189
-rw-r--r--src/tools/miri/src/shims/unix/fs.rs322
-rw-r--r--src/tools/miri/src/shims/unix/linux/epoll.rs4
-rw-r--r--src/tools/miri/src/shims/unix/linux/eventfd.rs6
-rw-r--r--src/tools/miri/src/shims/unix/linux/foreign_items.rs11
-rw-r--r--src/tools/miri/src/shims/unix/linux/mem.rs2
-rw-r--r--src/tools/miri/src/shims/unix/socket.rs6
-rw-r--r--src/tools/miri/src/shims/unix/sync.rs94
-rw-r--r--src/tools/miri/src/shims/unix/thread.rs23
-rw-r--r--src/tools/miri/src/shims/windows/env.rs5
-rw-r--r--src/tools/miri/src/shims/windows/foreign_items.rs8
-rw-r--r--src/tools/miri/src/shims/x86/mod.rs2
-rw-r--r--src/tools/miri/test_dependencies/Cargo.lock217
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs3
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.stderr10
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs3
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.stderr10
-rw-r--r--src/tools/miri/tests/fail-dep/libc/affinity.stderr4
-rw-r--r--src/tools/miri/tests/fail-dep/libc/memchr_null.rs2
-rw-r--r--src/tools/miri/tests/fail-dep/libc/memchr_null.stderr4
-rw-r--r--src/tools/miri/tests/fail-dep/libc/memcmp_null.rs2
-rw-r--r--src/tools/miri/tests/fail-dep/libc/memcmp_null.stderr4
-rw-r--r--src/tools/miri/tests/fail-dep/libc/memcmp_zero.stderr4
-rw-r--r--src/tools/miri/tests/fail-dep/libc/memcpy_zero.stderr4
-rw-r--r--src/tools/miri/tests/fail-dep/libc/memrchr_null.rs2
-rw-r--r--src/tools/miri/tests/fail-dep/libc/memrchr_null.stderr4
-rw-r--r--src/tools/miri/tests/fail-dep/tokio/sleep.stderr2
-rw-r--r--src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.rs2
-rw-r--r--src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr4
-rw-r--r--src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr4
-rw-r--r--src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr4
-rw-r--r--src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr4
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr4
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr4
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.rs2
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.stderr4
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.rs2
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.stderr4
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.stderr4
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.rs2
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr4
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs2
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr4
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr4
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/wild_pointer_deref.stderr4
-rw-r--r--src/tools/miri/tests/fail/extern-type-field-offset.stderr13
-rw-r--r--src/tools/miri/tests/fail/function_calls/check_callback_abi.rs2
-rw-r--r--src/tools/miri/tests/fail/function_calls/check_callback_abi.stderr4
-rw-r--r--src/tools/miri/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_1.rs7
-rw-r--r--src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_2.stderr15
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr10
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs2
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs3
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs1
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.rs (renamed from src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_2.rs)2
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.stderr (renamed from src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr)10
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.rs (renamed from src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_3.rs)2
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.stderr (renamed from src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr)10
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.rs9
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.stderr13
-rw-r--r--src/tools/miri/tests/fail/intrinsics/raw_eq_on_ptr.rs10
-rw-r--r--src/tools/miri/tests/fail/intrinsics/raw_eq_on_ptr.stderr15
-rw-r--r--src/tools/miri/tests/fail/intrinsics/simd-gather.rs3
-rw-r--r--src/tools/miri/tests/fail/intrinsics/simd-gather.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/simd-scatter.rs2
-rw-r--r--src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr4
-rw-r--r--src/tools/miri/tests/fail/miri_start_wrong_sig.rs21
-rw-r--r--src/tools/miri/tests/fail/miri_start_wrong_sig.stderr15
-rw-r--r--src/tools/miri/tests/fail/no_main.rs2
-rw-r--r--src/tools/miri/tests/fail/no_main.stderr9
-rw-r--r--src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr4
-rw-r--r--src/tools/miri/tests/fail/provenance/provenance_transmute.stderr4
-rw-r--r--src/tools/miri/tests/fail/provenance/ptr_int_unexposed.stderr4
-rw-r--r--src/tools/miri/tests/fail/provenance/ptr_invalid.stderr4
-rw-r--r--src/tools/miri/tests/fail/provenance/ptr_invalid_offset.stderr4
-rw-r--r--src/tools/miri/tests/fail/reading_half_a_pointer.stderr4
-rw-r--r--src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.rs2
-rw-r--r--src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr4
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr6
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs107
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr40
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.without.stderr40
-rw-r--r--src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.rs8
-rw-r--r--src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.stderr15
-rw-r--r--src/tools/miri/tests/fail/zst_local_oob.rs2
-rw-r--r--src/tools/miri/tests/fail/zst_local_oob.stderr4
-rw-r--r--src/tools/miri/tests/pass-dep/libc/gettid.rs22
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-fs-flock.rs70
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-fs-symlink.rs (renamed from src/tools/miri/tests/pass-dep/libc/libc-fs-readlink.rs)20
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-fs.rs9
-rw-r--r--src/tools/miri/tests/pass/adjacent-allocs.rs2
-rw-r--r--src/tools/miri/tests/pass/alloc-access-tracking.rs4
-rw-r--r--src/tools/miri/tests/pass/async-fn.rs1
-rw-r--r--src/tools/miri/tests/pass/box.rs3
-rw-r--r--src/tools/miri/tests/pass/box.stack.stderr33
-rw-r--r--src/tools/miri/tests/pass/box.stdout (renamed from src/tools/miri/tests/pass/box.stack.stdout)0
-rw-r--r--src/tools/miri/tests/pass/box.tree.stdout3
-rw-r--r--src/tools/miri/tests/pass/dyn-traits.rs10
-rw-r--r--src/tools/miri/tests/pass/enums.rs1
-rw-r--r--src/tools/miri/tests/pass/extern_types.rs8
-rw-r--r--src/tools/miri/tests/pass/extern_types.stack.stderr13
-rw-r--r--src/tools/miri/tests/pass/function_pointers.rs3
-rw-r--r--src/tools/miri/tests/pass/getpid.rs15
-rw-r--r--src/tools/miri/tests/pass/intptrcast.rs2
-rw-r--r--src/tools/miri/tests/pass/miri_start.rs19
-rw-r--r--src/tools/miri/tests/pass/miri_start.stdout1
-rw-r--r--src/tools/miri/tests/pass/pointers.rs2
-rw-r--r--src/tools/miri/tests/pass/ptr_int_casts.rs3
-rw-r--r--src/tools/miri/tests/pass/ptr_int_casts.tree.stderr89
-rw-r--r--src/tools/miri/tests/pass/ptr_int_from_exposed.rs12
-rw-r--r--src/tools/miri/tests/pass/ptr_int_from_exposed.tree.stderr19
-rw-r--r--src/tools/miri/tests/pass/rc.rs3
-rw-r--r--src/tools/miri/tests/pass/shims/fs.rs41
-rw-r--r--src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr10
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/reserved.stderr2
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/vec_unique.rs2
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/vec_unique.uniq.stderr8
-rw-r--r--src/tools/miri/tests/ui.rs2
-rw-r--r--src/tools/opt-dist/Cargo.toml2
-rw-r--r--src/tools/opt-dist/src/bolt.rs3
-rw-r--r--src/tools/opt-dist/src/exec.rs10
-rw-r--r--src/tools/opt-dist/src/main.rs2
-rw-r--r--src/tools/opt-dist/src/metrics.rs6
-rw-r--r--src/tools/opt-dist/src/tests.rs36
-rw-r--r--src/tools/opt-dist/src/training.rs9
-rw-r--r--src/tools/opt-dist/src/utils/artifact_size.rs4
-rw-r--r--src/tools/opt-dist/src/utils/io.rs5
-rw-r--r--src/tools/opt-dist/src/utils/mod.rs5
-rw-r--r--src/tools/remote-test-client/src/main.rs3
-rw-r--r--src/tools/remote-test-server/src/main.rs13
-rw-r--r--src/tools/replace-version-placeholder/src/main.rs1
-rw-r--r--src/tools/rls/src/main.rs6
-rw-r--r--src/tools/run-make-support/Cargo.toml4
-rw-r--r--src/tools/run-make-support/src/artifact_names.rs11
-rw-r--r--src/tools/run-make-support/src/assertion_helpers.rs32
-rw-r--r--src/tools/run-make-support/src/command.rs50
-rw-r--r--src/tools/run-make-support/src/diff/mod.rs43
-rw-r--r--src/tools/run-make-support/src/env.rs7
-rw-r--r--src/tools/run-make-support/src/external_deps/c_build.rs55
-rw-r--r--src/tools/run-make-support/src/external_deps/cc.rs22
-rw-r--r--src/tools/run-make-support/src/external_deps/clang.rs5
-rw-r--r--src/tools/run-make-support/src/external_deps/cygpath.rs35
-rw-r--r--src/tools/run-make-support/src/external_deps/htmldocck.rs3
-rw-r--r--src/tools/run-make-support/src/external_deps/llvm.rs75
-rw-r--r--src/tools/run-make-support/src/external_deps/mod.rs3
-rw-r--r--src/tools/run-make-support/src/external_deps/rustc.rs59
-rw-r--r--src/tools/run-make-support/src/fs.rs26
-rw-r--r--src/tools/run-make-support/src/lib.rs17
-rw-r--r--src/tools/run-make-support/src/path_helpers.rs8
-rw-r--r--src/tools/run-make-support/src/run.rs3
-rw-r--r--src/tools/run-make-support/src/symbols.rs44
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs1
-rw-r--r--src/tools/rust-analyzer/rust-version2
-rw-r--r--src/tools/rust-installer/src/combiner.rs13
-rw-r--r--src/tools/rust-installer/src/compression.rs12
-rw-r--r--src/tools/rust-installer/src/generator.rs11
-rw-r--r--src/tools/rust-installer/src/scripter.rs6
-rw-r--r--src/tools/rust-installer/src/tarballer.rs9
-rw-r--r--src/tools/rust-installer/src/util.rs15
-rw-r--r--src/tools/rustbook/Cargo.lock21
-rw-r--r--src/tools/rustbook/Cargo.toml1
-rw-r--r--src/tools/rustbook/src/main.rs18
m---------src/tools/rustc-perf0
-rw-r--r--src/tools/rustc-perf-wrapper/src/main.rs122
-rw-r--r--src/tools/rustdoc-gui-test/src/config.rs4
-rw-r--r--src/tools/rustdoc-gui-test/src/main.rs7
-rw-r--r--src/tools/rustdoc/main.rs3
-rw-r--r--src/tools/rustfmt/src/git-rustfmt/main.rs4
-rw-r--r--src/tools/rustfmt/src/parse/macros/lazy_static.rs12
-rw-r--r--src/tools/rustfmt/tests/source/cfg_if/detect/os/x86.rs9
-rw-r--r--src/tools/rustfmt/tests/target/cfg_if/detect/os/x86.rs9
-rw-r--r--src/tools/suggest-tests/src/lib.rs6
-rw-r--r--src/tools/suggest-tests/src/static_suggestions.rs3
-rw-r--r--src/tools/tidy/src/allowed_run_make_makefiles.txt38
-rw-r--r--src/tools/tidy/src/alphabetical/tests.rs3
-rw-r--r--src/tools/tidy/src/bins.rs3
-rw-r--r--src/tools/tidy/src/debug_artifacts.rs3
-rw-r--r--src/tools/tidy/src/deps.rs113
-rw-r--r--src/tools/tidy/src/edition.rs17
-rw-r--r--src/tools/tidy/src/error_codes.rs6
-rw-r--r--src/tools/tidy/src/ext_tool_checks.rs4
-rw-r--r--src/tools/tidy/src/features.rs6
-rw-r--r--src/tools/tidy/src/fluent_alphabetical.rs7
-rw-r--r--src/tools/tidy/src/fluent_period.rs3
-rw-r--r--src/tools/tidy/src/fluent_used.rs3
-rw-r--r--src/tools/tidy/src/known_bug.rs3
-rw-r--r--src/tools/tidy/src/lib.rs1
-rw-r--r--src/tools/tidy/src/main.rs7
-rw-r--r--src/tools/tidy/src/mir_opt_tests.rs3
-rw-r--r--src/tools/tidy/src/pal.rs3
-rw-r--r--src/tools/tidy/src/style.rs8
-rw-r--r--src/tools/tidy/src/target_policy.rs4
-rw-r--r--src/tools/tidy/src/ui_tests.rs3
-rw-r--r--src/tools/tidy/src/unit_tests.rs3
-rw-r--r--src/tools/tidy/src/unstable_book.rs3
-rw-r--r--src/tools/tidy/src/walk.rs7
-rw-r--r--src/tools/tidy/src/x_version.rs3
-rw-r--r--src/tools/unicode-table-generator/src/cascading_map.rs5
-rw-r--r--src/tools/unicode-table-generator/src/case_mapping.rs9
-rw-r--r--src/tools/unicode-table-generator/src/main.rs1
-rw-r--r--src/tools/unicode-table-generator/src/raw_emitter.rs3
-rw-r--r--src/tools/unicode-table-generator/src/skiplist.rs5
-rw-r--r--src/tools/unicode-table-generator/src/unicode_download.rs3
-rw-r--r--src/tools/unstable-book-gen/src/main.rs1
-rw-r--r--src/tools/x/src/main.rs11
740 files changed, 12802 insertions, 8123 deletions
diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock
index de0924c0f42..60453764d82 100644
--- a/src/bootstrap/Cargo.lock
+++ b/src/bootstrap/Cargo.lock
@@ -65,7 +65,7 @@ dependencies = [
  "termcolor",
  "toml",
  "walkdir",
- "windows",
+ "windows 0.52.0",
  "xz2",
 ]
 
@@ -379,12 +379,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "once_cell"
-version = "1.19.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
-
-[[package]]
 name = "opener"
 version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -549,16 +543,15 @@ dependencies = [
 
 [[package]]
 name = "sysinfo"
-version = "0.30.5"
+version = "0.31.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fb4f3438c8f6389c864e61221cbc97e9bca98b4daf39a5beb7bea660f528bb2"
+checksum = "d4115055da5f572fff541dd0c4e61b0262977f453cc9fe04be83aba25a89bdab"
 dependencies = [
- "cfg-if",
  "core-foundation-sys",
  "libc",
+ "memchr",
  "ntapi",
- "once_cell",
- "windows",
+ "windows 0.57.0",
 ]
 
 [[package]]
@@ -655,7 +648,17 @@ version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
 dependencies = [
- "windows-core",
+ "windows-core 0.52.0",
+ "windows-targets",
+]
+
+[[package]]
+name = "windows"
+version = "0.57.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143"
+dependencies = [
+ "windows-core 0.57.0",
  "windows-targets",
 ]
 
@@ -669,6 +672,49 @@ dependencies = [
 ]
 
 [[package]]
+name = "windows-core"
+version = "0.57.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d"
+dependencies = [
+ "windows-implement",
+ "windows-interface",
+ "windows-result",
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-implement"
+version = "0.57.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "windows-interface"
+version = "0.57.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "windows-result"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
 name = "windows-sys"
 version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -679,13 +725,14 @@ dependencies = [
 
 [[package]]
 name = "windows-targets"
-version = "0.52.0"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
 dependencies = [
  "windows_aarch64_gnullvm",
  "windows_aarch64_msvc",
  "windows_i686_gnu",
+ "windows_i686_gnullvm",
  "windows_i686_msvc",
  "windows_x86_64_gnu",
  "windows_x86_64_gnullvm",
@@ -694,45 +741,51 @@ dependencies = [
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.52.0"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.52.0"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.52.0"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.52.0"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.52.0"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.52.0"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.52.0"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 
 [[package]]
 name = "xattr"
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index f723407c3ce..84262c115b1 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -63,7 +63,7 @@ walkdir = "2.4"
 xz2 = "0.1"
 
 # Dependencies needed by the build-metrics feature
-sysinfo = { version = "0.30", default-features = false, optional = true }
+sysinfo = { version = "0.31.2", default-features = false, optional = true, features = ["system"] }
 
 [target.'cfg(windows)'.dependencies.junction]
 version = "1.0.0"
diff --git a/src/bootstrap/download-ci-llvm-stamp b/src/bootstrap/download-ci-llvm-stamp
index 258a0347451..11316004412 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/126298
+Last change is for: https://github.com/rust-lang/rust/pull/125642
diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs
index a7d21ba6ae1..f03f03e2d93 100644
--- a/src/bootstrap/src/bin/main.rs
+++ b/src/bootstrap/src/bin/main.rs
@@ -5,23 +5,25 @@
 //! parent directory, and otherwise documentation can be found throughout the `build`
 //! directory in each respective module.
 
-use std::io::Write;
-use std::process;
+use std::fs::{self, OpenOptions};
+use std::io::{self, BufRead, BufReader, IsTerminal, Write};
 use std::str::FromStr;
-use std::{
-    env,
-    fs::{self, OpenOptions},
-    io::{self, BufRead, BufReader, IsTerminal},
-};
+use std::{env, process};
 
 use bootstrap::{
-    find_recent_config_change_ids, human_readable_changes, t, Build, Config, Subcommand,
+    find_recent_config_change_ids, human_readable_changes, t, Build, Config, Flags, Subcommand,
     CONFIG_CHANGE_HISTORY,
 };
 
 fn main() {
     let args = env::args().skip(1).collect::<Vec<_>>();
-    let config = Config::parse(&args);
+
+    if Flags::try_parse_verbose_help(&args) {
+        return;
+    }
+
+    let flags = Flags::parse(&args);
+    let config = Config::parse(flags);
 
     let mut build_lock;
     let _build_lock_guard;
@@ -30,10 +32,7 @@ fn main() {
         // Display PID of process holding the lock
         // PID will be stored in a lock file
         let lock_path = config.out.join("lock");
-        let pid = match fs::read_to_string(&lock_path) {
-            Ok(contents) => contents,
-            Err(_) => String::new(),
-        };
+        let pid = fs::read_to_string(&lock_path).unwrap_or_default();
 
         build_lock = fd_lock::RwLock::new(t!(fs::OpenOptions::new()
             .write(true)
diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs
index 46e845f77ae..d04e2fbeb78 100644
--- a/src/bootstrap/src/bin/rustc.rs
+++ b/src/bootstrap/src/bin/rustc.rs
@@ -89,6 +89,25 @@ fn main() {
         rustc_real
     };
 
+    // Get the name of the crate we're compiling, if any.
+    let crate_name = parse_value_from_args(&orig_args, "--crate-name");
+
+    // When statically linking `std` into `rustc_driver`, remove `-C prefer-dynamic`
+    if env::var("RUSTC_LINK_STD_INTO_RUSTC_DRIVER").unwrap() == "1"
+        && crate_name == Some("rustc_driver")
+        && stage != "0"
+    {
+        if let Some(pos) = args.iter().enumerate().position(|(i, a)| {
+            a == "-C" && args.get(i + 1).map(|a| a == "prefer-dynamic").unwrap_or(false)
+        }) {
+            args.remove(pos);
+            args.remove(pos);
+        }
+        if let Some(pos) = args.iter().position(|a| a == "-Cprefer-dynamic") {
+            args.remove(pos);
+        }
+    }
+
     let mut cmd = match env::var_os("RUSTC_WRAPPER_REAL") {
         Some(wrapper) if !wrapper.is_empty() => {
             let mut cmd = Command::new(wrapper);
@@ -99,9 +118,6 @@ 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 = parse_value_from_args(&orig_args, "--crate-name");
-
     if let Some(crate_name) = crate_name {
         if let Some(target) = env::var_os("RUSTC_TIME") {
             if target == "all"
@@ -315,12 +331,10 @@ fn format_rusage_data(_child: Child) -> Option<String> {
 fn format_rusage_data(child: Child) -> Option<String> {
     use std::os::windows::io::AsRawHandle;
 
-    use windows::{
-        Win32::Foundation::HANDLE,
-        Win32::System::ProcessStatus::{K32GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS},
-        Win32::System::Threading::GetProcessTimes,
-        Win32::System::Time::FileTimeToSystemTime,
-    };
+    use windows::Win32::Foundation::HANDLE;
+    use windows::Win32::System::ProcessStatus::{K32GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS};
+    use windows::Win32::System::Threading::GetProcessTimes;
+    use windows::Win32::System::Time::FileTimeToSystemTime;
 
     let handle = HANDLE(child.as_raw_handle() as isize);
 
diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs
index ed5b9edc86d..7f7faf077d0 100644
--- a/src/bootstrap/src/core/build_steps/check.rs
+++ b/src/bootstrap/src/core/build_steps/check.rs
@@ -1,7 +1,9 @@
 //! Implementation of compiling the compiler and standard library, in "check"-based modes.
 
+use std::path::PathBuf;
+
 use crate::core::build_steps::compile::{
-    add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo,
+    add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, std_crates_for_run_make,
 };
 use crate::core::build_steps::tool::{prepare_tool_cargo, SourceType};
 use crate::core::builder::{
@@ -9,17 +11,6 @@ use crate::core::builder::{
 };
 use crate::core::config::TargetSelection;
 use crate::{Compiler, Mode, Subcommand};
-use std::path::{Path, PathBuf};
-
-pub fn cargo_subcommand(kind: Kind) -> &'static str {
-    match kind {
-        Kind::Check
-        // We ensure check steps for both std and rustc from build_steps/clippy, so handle `Kind::Clippy` as well.
-        | Kind::Clippy => "check",
-        Kind::Fix => "fix",
-        _ => unreachable!(),
-    }
-}
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct Std {
@@ -30,11 +21,18 @@ pub struct Std {
     ///
     /// [`compile::Rustc`]: crate::core::build_steps::compile::Rustc
     crates: Vec<String>,
+    /// Override `Builder::kind` on cargo invocations.
+    ///
+    /// By default, `Builder::kind` is propagated as the subcommand to the cargo invocations.
+    /// However, there are cases when this is not desirable. For example, when running `x clippy $tool_name`,
+    /// passing `Builder::kind` to cargo invocations would run clippy on the entire compiler and library,
+    /// which is not useful if we only want to lint a few crates with specific rules.
+    override_build_kind: Option<Kind>,
 }
 
 impl Std {
-    pub fn new(target: TargetSelection) -> Self {
-        Self { target, crates: vec![] }
+    pub fn new_with_build_kind(target: TargetSelection, kind: Option<Kind>) -> Self {
+        Self { target, crates: vec![], override_build_kind: kind }
     }
 }
 
@@ -47,12 +45,12 @@ impl Step for Std {
     }
 
     fn make_run(run: RunConfig<'_>) {
-        let crates = run.make_run_crates(Alias::Library);
-        run.builder.ensure(Std { target: run.target, crates });
+        let crates = std_crates_for_run_make(&run);
+        run.builder.ensure(Std { target: run.target, crates, override_build_kind: None });
     }
 
     fn run(self, builder: &Builder<'_>) {
-        builder.update_submodule(&Path::new("library").join("stdarch"));
+        builder.require_submodule("library/stdarch", None);
 
         let target = self.target;
         let compiler = builder.compiler(builder.top_stage, builder.config.build);
@@ -63,7 +61,7 @@ impl Step for Std {
             Mode::Std,
             SourceType::InTree,
             target,
-            cargo_subcommand(builder.kind),
+            self.override_build_kind.unwrap_or(builder.kind),
         );
 
         std_cargo(builder, target, compiler.stage, &mut cargo);
@@ -117,7 +115,7 @@ impl Step for Std {
             Mode::Std,
             SourceType::InTree,
             target,
-            cargo_subcommand(builder.kind),
+            self.override_build_kind.unwrap_or(builder.kind),
         );
 
         // If we're not in stage 0, tests and examples will fail to compile
@@ -158,16 +156,31 @@ pub struct Rustc {
     ///
     /// [`compile::Rustc`]: crate::core::build_steps::compile::Rustc
     crates: Vec<String>,
+    /// Override `Builder::kind` on cargo invocations.
+    ///
+    /// By default, `Builder::kind` is propagated as the subcommand to the cargo invocations.
+    /// However, there are cases when this is not desirable. For example, when running `x clippy $tool_name`,
+    /// passing `Builder::kind` to cargo invocations would run clippy on the entire compiler and library,
+    /// which is not useful if we only want to lint a few crates with specific rules.
+    override_build_kind: Option<Kind>,
 }
 
 impl Rustc {
     pub fn new(target: TargetSelection, builder: &Builder<'_>) -> Self {
+        Self::new_with_build_kind(target, builder, None)
+    }
+
+    pub fn new_with_build_kind(
+        target: TargetSelection,
+        builder: &Builder<'_>,
+        kind: Option<Kind>,
+    ) -> Self {
         let crates = builder
             .in_tree_crates("rustc-main", Some(target))
             .into_iter()
             .map(|krate| krate.name.to_string())
             .collect();
-        Self { target, crates }
+        Self { target, crates, override_build_kind: kind }
     }
 }
 
@@ -182,7 +195,7 @@ impl Step for Rustc {
 
     fn make_run(run: RunConfig<'_>) {
         let crates = run.make_run_crates(Alias::Compiler);
-        run.builder.ensure(Rustc { target: run.target, crates });
+        run.builder.ensure(Rustc { target: run.target, crates, override_build_kind: None });
     }
 
     /// Builds the compiler.
@@ -203,7 +216,7 @@ impl Step for Rustc {
             builder.ensure(crate::core::build_steps::compile::Std::new(compiler, compiler.host));
             builder.ensure(crate::core::build_steps::compile::Std::new(compiler, target));
         } else {
-            builder.ensure(Std::new(target));
+            builder.ensure(Std::new_with_build_kind(target, self.override_build_kind));
         }
 
         let mut cargo = builder::Cargo::new(
@@ -212,7 +225,7 @@ impl Step for Rustc {
             Mode::Rustc,
             SourceType::InTree,
             target,
-            cargo_subcommand(builder.kind),
+            self.override_build_kind.unwrap_or(builder.kind),
         );
 
         rustc_cargo(builder, &mut cargo, target, &compiler);
@@ -290,7 +303,7 @@ impl Step for CodegenBackend {
             Mode::Codegen,
             SourceType::InTree,
             target,
-            cargo_subcommand(builder.kind),
+            builder.kind,
         );
 
         cargo
@@ -348,7 +361,7 @@ impl Step for RustAnalyzer {
             compiler,
             Mode::ToolRustc,
             target,
-            cargo_subcommand(builder.kind),
+            builder.kind,
             "src/tools/rust-analyzer",
             SourceType::InTree,
             &["in-rust-tree".to_owned()],
@@ -416,7 +429,7 @@ macro_rules! tool_check_step {
                     compiler,
                     Mode::ToolRustc,
                     target,
-                    cargo_subcommand(builder.kind),
+                    builder.kind,
                     $path,
                     $source_type,
                     &[],
diff --git a/src/bootstrap/src/core/build_steps/clean.rs b/src/bootstrap/src/core/build_steps/clean.rs
index a4be6bc56c5..f608e5d715e 100644
--- a/src/bootstrap/src/core/build_steps/clean.rs
+++ b/src/bootstrap/src/core/build_steps/clean.rs
@@ -11,7 +11,7 @@ use std::path::Path;
 
 use crate::core::builder::{crate_description, Builder, RunConfig, ShouldRun, Step};
 use crate::utils::helpers::t;
-use crate::{Build, Compiler, Mode, Subcommand};
+use crate::{Build, Compiler, Kind, Mode, Subcommand};
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct CleanAll {}
@@ -66,7 +66,7 @@ macro_rules! clean_crate_tree {
             fn run(self, builder: &Builder<'_>) -> Self::Output {
                 let compiler = self.compiler;
                 let target = compiler.host;
-                let mut cargo = builder.bare_cargo(compiler, $mode, target, "clean");
+                let mut cargo = builder.bare_cargo(compiler, $mode, target, Kind::Clean);
 
                 // Since https://github.com/rust-lang/rust/pull/111076 enables
                 // unstable cargo feature (`public-dependency`), we need to ensure
@@ -121,7 +121,7 @@ fn clean(build: &Build, all: bool, stage: Option<u32>) {
 
 fn clean_specific_stage(build: &Build, stage: u32) {
     for host in &build.hosts {
-        let entries = match build.out.join(host.triple).read_dir() {
+        let entries = match build.out.join(host).read_dir() {
             Ok(iter) => iter,
             Err(_) => continue,
         };
@@ -148,7 +148,7 @@ fn clean_default(build: &Build) {
     rm_rf(&build.out.join("bootstrap-shims-dump"));
     rm_rf(&build.out.join("rustfmt.stamp"));
 
-    let mut hosts: Vec<_> = build.hosts.iter().map(|t| build.out.join(t.triple)).collect();
+    let mut hosts: Vec<_> = build.hosts.iter().map(|t| build.out.join(t)).collect();
     // After cross-compilation, artifacts of the host architecture (which may differ from build.host)
     // might not get removed.
     // Adding its path (linked one for easier accessibility) will solve this problem.
diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs
index ee7fb368a8c..4ee9fbc3142 100644
--- a/src/bootstrap/src/core/build_steps/clippy.rs
+++ b/src/bootstrap/src/core/build_steps/clippy.rs
@@ -1,28 +1,13 @@
 //! Implementation of running clippy on the compiler, standard library and various tools.
 
-use std::path::Path;
-
-use crate::builder::Builder;
-use crate::builder::ShouldRun;
+use super::compile::{librustc_stamp, libstd_stamp, run_cargo, rustc_cargo, std_cargo};
+use super::tool::{prepare_tool_cargo, SourceType};
+use super::{check, compile};
+use crate::builder::{Builder, ShouldRun};
+use crate::core::build_steps::compile::std_crates_for_run_make;
 use crate::core::builder;
-use crate::core::builder::crate_description;
-use crate::core::builder::Alias;
-use crate::core::builder::Kind;
-use crate::core::builder::RunConfig;
-use crate::core::builder::Step;
-use crate::Mode;
-use crate::Subcommand;
-use crate::TargetSelection;
-
-use super::check;
-use super::compile;
-use super::compile::librustc_stamp;
-use super::compile::libstd_stamp;
-use super::compile::run_cargo;
-use super::compile::rustc_cargo;
-use super::compile::std_cargo;
-use super::tool::prepare_tool_cargo;
-use super::tool::SourceType;
+use crate::core::builder::{crate_description, Alias, Kind, RunConfig, Step};
+use crate::{Mode, Subcommand, TargetSelection};
 
 /// Disable the most spammy clippy lints
 const IGNORED_RULES_FOR_STD_AND_RUSTC: &[&str] = &[
@@ -122,18 +107,24 @@ impl Step for Std {
     }
 
     fn make_run(run: RunConfig<'_>) {
-        let crates = run.make_run_crates(Alias::Library);
+        let crates = std_crates_for_run_make(&run);
         run.builder.ensure(Std { target: run.target, crates });
     }
 
     fn run(self, builder: &Builder<'_>) {
-        builder.update_submodule(&Path::new("library").join("stdarch"));
+        builder.require_submodule("library/stdarch", None);
 
         let target = self.target;
         let compiler = builder.compiler(builder.top_stage, builder.config.build);
 
-        let mut cargo =
-            builder::Cargo::new(builder, compiler, Mode::Std, SourceType::InTree, target, "clippy");
+        let mut cargo = builder::Cargo::new(
+            builder,
+            compiler,
+            Mode::Std,
+            SourceType::InTree,
+            target,
+            Kind::Clippy,
+        );
 
         std_cargo(builder, target, compiler.stage, &mut cargo);
 
@@ -194,7 +185,7 @@ impl Step for Rustc {
             builder.ensure(compile::Std::new(compiler, compiler.host));
             builder.ensure(compile::Std::new(compiler, target));
         } else {
-            builder.ensure(check::Std::new(target));
+            builder.ensure(check::Std::new_with_build_kind(target, Some(Kind::Check)));
         }
 
         let mut cargo = builder::Cargo::new(
@@ -203,7 +194,7 @@ impl Step for Rustc {
             Mode::Rustc,
             SourceType::InTree,
             target,
-            "clippy",
+            Kind::Clippy,
         );
 
         rustc_cargo(builder, &mut cargo, target, &compiler);
@@ -261,14 +252,14 @@ macro_rules! lint_any {
                 let compiler = builder.compiler(builder.top_stage, builder.config.build);
                 let target = self.target;
 
-                builder.ensure(check::Rustc::new(target, builder));
+                builder.ensure(check::Rustc::new_with_build_kind(target, builder, Some(Kind::Check)));
 
                 let cargo = prepare_tool_cargo(
                     builder,
                     compiler,
                     Mode::ToolRustc,
                     target,
-                    "clippy",
+                    Kind::Clippy,
                     $path,
                     SourceType::InTree,
                     &[],
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 25adaa0aa86..4353cfadd8d 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -8,31 +8,28 @@
 
 use std::borrow::Cow;
 use std::collections::HashSet;
-use std::env;
 use std::ffi::OsStr;
-use std::fs;
 use std::io::prelude::*;
 use std::io::BufReader;
 use std::path::{Path, PathBuf};
 use std::process::Stdio;
-use std::str;
+use std::{env, fs, str};
 
 use serde_derive::Deserialize;
 
-use crate::core::build_steps::dist;
-use crate::core::build_steps::llvm;
 use crate::core::build_steps::tool::SourceType;
+use crate::core::build_steps::{dist, llvm};
 use crate::core::builder;
-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::builder::{
+    crate_description, Builder, Cargo, 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, symlink_dir, t, up_to_date,
+    self, exe, get_clang_cl_resource_dir, get_closest_merge_base_commit, is_debug_info, is_dylib,
+    symlink_dir, t, up_to_date,
 };
-use crate::LLVM_TOOLS;
-use crate::{CLang, Compiler, DependencyType, GitRepo, Mode};
+use crate::{CLang, Compiler, DependencyType, GitRepo, Mode, LLVM_TOOLS};
 
 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct Std {
@@ -118,25 +115,43 @@ impl Step for Std {
     const DEFAULT: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        // When downloading stage1, the standard library has already been copied to the sysroot, so
-        // there's no need to rebuild it.
-        let builder = run.builder;
-        run.crate_or_deps("sysroot")
-            .path("library")
-            .lazy_default_condition(Box::new(|| !builder.download_rustc()))
+        run.crate_or_deps("sysroot").path("library")
     }
 
     fn make_run(run: RunConfig<'_>) {
-        // If the paths include "library", build the entire standard library.
-        let has_alias =
-            run.paths.iter().any(|set| set.assert_single_path().path.ends_with("library"));
-        let crates = if has_alias { Default::default() } else { run.cargo_crates_in_set() };
+        let crates = std_crates_for_run_make(&run);
+        let builder = run.builder;
+
+        // Force compilation of the standard library from source if the `library` is modified. This allows
+        // library team to compile the standard library without needing to compile the compiler with
+        // the `rust.download-rustc=true` option.
+        let force_recompile =
+            if builder.rust_info().is_managed_git_subrepository() && builder.download_rustc() {
+                let closest_merge_commit = get_closest_merge_base_commit(
+                    Some(&builder.src),
+                    &builder.config.git_config(),
+                    &builder.config.stage0_metadata.config.git_merge_commit_email,
+                    &[],
+                )
+                .unwrap();
+
+                // Check if `library` has changes (returns false otherwise)
+                !t!(helpers::git(Some(&builder.src))
+                    .args(["diff-index", "--quiet", &closest_merge_commit])
+                    .arg("--")
+                    .arg(builder.src.join("library"))
+                    .as_command_mut()
+                    .status())
+                .success()
+            } else {
+                false
+            };
 
         run.builder.ensure(Std {
             compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()),
             target: run.target,
             crates,
-            force_recompile: false,
+            force_recompile,
             extra_rust_args: &[],
             is_for_mir_opt_tests: false,
         });
@@ -182,11 +197,16 @@ impl Step for Std {
             return;
         }
 
-        builder.update_submodule(&Path::new("library").join("stdarch"));
+        builder.require_submodule("library/stdarch", None);
 
         // Profiler information requires LLVM's compiler-rt
         if builder.config.profiler {
-            builder.update_submodule(Path::new("src/llvm-project"));
+            builder.require_submodule(
+                "src/llvm-project",
+                Some(
+                    "The `build.profiler` config option requires `compiler-rt` sources from LLVM.",
+                ),
+            );
         }
 
         let mut target_deps = builder.ensure(StartupObjects { compiler, target });
@@ -226,7 +246,7 @@ impl Step for Std {
                 .rustc_snapshot_sysroot()
                 .join("lib")
                 .join("rustlib")
-                .join(compiler.host.triple)
+                .join(compiler.host)
                 .join("bin");
             if src_sysroot_bin.exists() {
                 let target_sysroot_bin =
@@ -246,7 +266,7 @@ impl Step for Std {
                 Mode::Std,
                 SourceType::InTree,
                 target,
-                "check",
+                Kind::Check,
             );
             cargo.rustflag("-Zalways-encode-mir");
             cargo.arg("--manifest-path").arg(builder.src.join("library/sysroot/Cargo.toml"));
@@ -258,7 +278,7 @@ impl Step for Std {
                 Mode::Std,
                 SourceType::InTree,
                 target,
-                "build",
+                Kind::Build,
             );
             std_cargo(builder, target, compiler.stage, &mut cargo);
             for krate in &*self.crates {
@@ -412,7 +432,7 @@ fn copy_self_contained_objects(
                 DependencyType::TargetSelfContained,
             );
         }
-    } else if target.ends_with("windows-gnu") {
+    } else if target.is_windows_gnu() {
         for obj in ["crt2.o", "dllcrt2.o"].iter() {
             let src = compiler_file(builder, &builder.cc(target), target, CLang::C, obj);
             let target = libdir_self_contained.join(obj);
@@ -424,6 +444,28 @@ fn copy_self_contained_objects(
     target_deps
 }
 
+/// Resolves standard library crates for `Std::run_make` for any build kind (like check, build, clippy, etc.).
+pub fn std_crates_for_run_make(run: &RunConfig<'_>) -> Vec<String> {
+    // FIXME: Extend builder tests to cover the `crates` field of `Std` instances.
+    if cfg!(feature = "bootstrap-self-test") {
+        return vec![];
+    }
+
+    let has_alias = run.paths.iter().any(|set| set.assert_single_path().path.ends_with("library"));
+    let target_is_no_std = run.builder.no_std(run.target).unwrap_or(false);
+
+    // For no_std targets, do not add any additional crates to the compilation other than what `compile::std_cargo` already adds for no_std targets.
+    if target_is_no_std {
+        vec![]
+    }
+    // If the paths include "library", build the entire standard library.
+    else if has_alias {
+        run.make_run_crates(builder::Alias::Library)
+    } else {
+        run.cargo_crates_in_set()
+    }
+}
+
 /// Configure cargo to compile the standard library, adding appropriate env vars
 /// and such.
 pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, cargo: &mut Cargo) {
@@ -456,13 +498,15 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car
         // That's probably ok? At least, the difference wasn't enforced before. There's a comment in
         // the compiler_builtins build script that makes me nervous, though:
         // https://github.com/rust-lang/compiler-builtins/blob/31ee4544dbe47903ce771270d6e3bea8654e9e50/build.rs#L575-L579
-        builder.update_submodule(&Path::new("src").join("llvm-project"));
+        builder.require_submodule(
+            "src/llvm-project",
+            Some(
+                "The `build.optimized-compiler-builtins` config option \
+                 requires `compiler-rt` sources from LLVM.",
+            ),
+        );
         let compiler_builtins_root = builder.src.join("src/llvm-project/compiler-rt");
-        if !compiler_builtins_root.exists() {
-            panic!(
-                "need LLVM sources available to build `compiler-rt`, but they weren't present; consider enabling `build.submodules = true` or disabling `optimized-compiler-builtins`"
-            );
-        }
+        assert!(compiler_builtins_root.exists());
         // Note that `libprofiler_builtins/build.rs` also computes this so if
         // you're changing something here please also change that.
         cargo.env("RUST_COMPILER_RT_ROOT", &compiler_builtins_root);
@@ -607,8 +651,8 @@ impl Step for StdLink {
                 compiler: self.compiler,
                 force_recompile: self.force_recompile,
             });
-            let libdir = sysroot.join(lib).join("rustlib").join(target.triple).join("lib");
-            let hostdir = sysroot.join(lib).join("rustlib").join(compiler.host.triple).join("lib");
+            let libdir = sysroot.join(lib).join("rustlib").join(target).join("lib");
+            let hostdir = sysroot.join(lib).join("rustlib").join(compiler.host).join("lib");
             (libdir, hostdir)
         } else {
             let libdir = builder.sysroot_libdir(target_compiler, target);
@@ -626,12 +670,12 @@ impl Step for StdLink {
                 .build
                 .config
                 .initial_rustc
-                .starts_with(builder.out.join(compiler.host.triple).join("stage0/bin"))
+                .starts_with(builder.out.join(compiler.host).join("stage0/bin"))
         {
             // Copy bin files from stage0/bin to stage0-sysroot/bin
-            let sysroot = builder.out.join(compiler.host.triple).join("stage0-sysroot");
+            let sysroot = builder.out.join(compiler.host).join("stage0-sysroot");
 
-            let host = compiler.host.triple;
+            let host = compiler.host;
             let stage0_bin_dir = builder.out.join(host).join("stage0/bin");
             let sysroot_bin_dir = sysroot.join("bin");
             t!(fs::create_dir_all(&sysroot_bin_dir));
@@ -749,7 +793,7 @@ impl Step for StartupObjects {
     fn run(self, builder: &Builder<'_>) -> Vec<(PathBuf, DependencyType)> {
         let for_compiler = self.compiler;
         let target = self.target;
-        if !target.ends_with("windows-gnu") {
+        if !target.is_windows_gnu() {
             return vec![];
         }
 
@@ -916,7 +960,7 @@ impl Step for Rustc {
             Mode::Rustc,
             SourceType::InTree,
             target,
-            "build",
+            Kind::Build,
         );
 
         rustc_cargo(builder, &mut cargo, target, &compiler);
@@ -1356,7 +1400,7 @@ impl Step for CodegenBackend {
             Mode::Codegen,
             SourceType::InTree,
             target,
-            "build",
+            Kind::Build,
         );
         cargo
             .arg("--manifest-path")
@@ -1510,7 +1554,7 @@ impl Step for Sysroot {
     /// For all other stages, it's the same stage directory that the compiler lives in.
     fn run(self, builder: &Builder<'_>) -> PathBuf {
         let compiler = self.compiler;
-        let host_dir = builder.out.join(compiler.host.triple);
+        let host_dir = builder.out.join(compiler.host);
 
         let sysroot_dir = |stage| {
             if stage == 0 {
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index 4076ed09256..530eb9b446a 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -9,19 +9,17 @@
 //! pieces of `rustup.rs`!
 
 use std::collections::HashSet;
-use std::env;
 use std::ffi::OsStr;
-use std::fs;
 use std::io::Write;
 use std::path::{Path, PathBuf};
+use std::{env, fs};
 
 use object::read::archive::ArchiveFile;
 use object::BinaryFormat;
 
-use crate::core::build_steps::compile;
 use crate::core::build_steps::doc::DocumentationFormat;
-use crate::core::build_steps::llvm;
 use crate::core::build_steps::tool::{self, Tool};
+use crate::core::build_steps::{compile, llvm};
 use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
 use crate::core::config::TargetSelection;
 use crate::utils::channel::{self, Info};
@@ -108,7 +106,6 @@ impl Step for JsonDocs {
         builder.ensure(crate::core::build_steps::doc::Std::new(
             builder.top_stage,
             host,
-            builder,
             DocumentationFormat::Json,
         ));
 
@@ -278,12 +275,8 @@ fn make_win_dist(
     }
 
     //Copy platform tools to platform-specific bin directory
-    let target_bin_dir = plat_root
-        .join("lib")
-        .join("rustlib")
-        .join(target.triple)
-        .join("bin")
-        .join("self-contained");
+    let target_bin_dir =
+        plat_root.join("lib").join("rustlib").join(target).join("bin").join("self-contained");
     fs::create_dir_all(&target_bin_dir).expect("creating target_bin_dir failed");
     for src in target_tools {
         builder.copy_link_to_folder(&src, &target_bin_dir);
@@ -298,12 +291,8 @@ fn make_win_dist(
     );
 
     //Copy platform libs to platform-specific lib directory
-    let target_lib_dir = plat_root
-        .join("lib")
-        .join("rustlib")
-        .join(target.triple)
-        .join("lib")
-        .join("self-contained");
+    let target_lib_dir =
+        plat_root.join("lib").join("rustlib").join(target).join("lib").join("self-contained");
     fs::create_dir_all(&target_lib_dir).expect("creating target_lib_dir failed");
     for src in target_libs {
         builder.copy_link_to_folder(&src, &target_lib_dir);
@@ -453,7 +442,7 @@ impl Step for Rustc {
             // component for now.
             maybe_install_llvm_runtime(builder, host, image);
 
-            let dst_dir = image.join("lib/rustlib").join(&*host.triple).join("bin");
+            let dst_dir = image.join("lib/rustlib").join(host).join("bin");
             t!(fs::create_dir_all(&dst_dir));
 
             // Copy over lld if it's there
@@ -610,7 +599,7 @@ fn verify_uefi_rlib_format(builder: &Builder<'_>, target: TargetSelection, stamp
 
 /// Copy stamped files into an image's `target/lib` directory.
 fn copy_target_libs(builder: &Builder<'_>, target: TargetSelection, image: &Path, stamp: &Path) {
-    let dst = image.join("lib/rustlib").join(target.triple).join("lib");
+    let dst = image.join("lib/rustlib").join(target).join("lib");
     let self_contained_dst = dst.join("self-contained");
     t!(fs::create_dir_all(&dst));
     t!(fs::create_dir_all(&self_contained_dst));
@@ -772,7 +761,7 @@ impl Step for Analysis {
 
         let src = builder
             .stage_out(compiler, Mode::Std)
-            .join(target.triple)
+            .join(target)
             .join(builder.cargo_dir())
             .join("deps")
             .join("save-analysis");
@@ -907,7 +896,7 @@ impl Step for Src {
     /// Creates the `rust-src` installer component
     fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
         if !builder.config.dry_run() {
-            builder.update_submodule(Path::new("src/llvm-project"));
+            builder.require_submodule("src/llvm-project", None);
         }
 
         let tarball = Tarball::new_targetless(builder, "rust-src");
@@ -921,7 +910,6 @@ impl Step for Src {
         // translation code in `imported_source_files` in `src/librustc_metadata/rmeta/decoder.rs`
         let dst_src = tarball.image_dir().join("lib/rustlib/src/rust");
 
-        let src_files = ["Cargo.lock"];
         // This is the reduced set of paths which will become the rust-src component
         // (essentially libstd and all of its path dependencies).
         copy_src_dirs(
@@ -940,9 +928,6 @@ impl Step for Src {
             ],
             &dst_src,
         );
-        for file in src_files.iter() {
-            builder.copy_link(&builder.src.join(file), &dst_src.join(file));
-        }
 
         tarball.generate()
     }
@@ -1022,10 +1007,7 @@ impl Step for PlainSourceTarball {
             // FIXME: This code looks _very_ similar to what we have in `src/core/build_steps/vendor.rs`
             // 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 build_helper::util::parse_gitmodules(&builder.src) {
-                builder.update_submodule(Path::new(submodule));
-            }
+            builder.require_and_update_all_submodules();
 
             // Vendor all Cargo dependencies
             let mut cmd = command(&builder.initial_cargo);
@@ -1040,6 +1022,8 @@ impl Step for PlainSourceTarball {
                 .arg("--sync")
                 .arg(builder.src.join("./compiler/rustc_codegen_gcc/Cargo.toml"))
                 .arg("--sync")
+                .arg(builder.src.join("./library/Cargo.toml"))
+                .arg("--sync")
                 .arg(builder.src.join("./src/bootstrap/Cargo.toml"))
                 .arg("--sync")
                 .arg(builder.src.join("./src/tools/opt-dist/Cargo.toml"))
@@ -1517,7 +1501,7 @@ impl Step for Extended {
         tarballs.push(builder.ensure(Rustc { compiler: builder.compiler(stage, target) }));
         tarballs.push(builder.ensure(Std { compiler, target }).expect("missing std"));
 
-        if target.ends_with("windows-gnu") {
+        if target.is_windows_gnu() {
             tarballs.push(builder.ensure(Mingw { host: target }).expect("missing mingw"));
         }
 
@@ -1691,7 +1675,7 @@ impl Step for Extended {
                     prepare(tool);
                 }
             }
-            if target.ends_with("windows-gnu") {
+            if target.is_windows_gnu() {
                 prepare("rust-mingw");
             }
 
@@ -1838,7 +1822,7 @@ impl Step for Extended {
                 .arg("-t")
                 .arg(etc.join("msi/remove-duplicates.xsl"))
                 .run(builder);
-            if target.ends_with("windows-gnu") {
+            if target.is_windows_gnu() {
                 command(&heat)
                     .current_dir(&exe)
                     .arg("dir")
@@ -1884,7 +1868,7 @@ impl Step for Extended {
                 if built_tools.contains("miri") {
                     cmd.arg("-dMiriDir=miri");
                 }
-                if target.ends_with("windows-gnu") {
+                if target.is_windows_gnu() {
                     cmd.arg("-dGccDir=rust-mingw");
                 }
                 cmd.run(builder);
@@ -1909,7 +1893,7 @@ impl Step for Extended {
             }
             candle("AnalysisGroup.wxs".as_ref());
 
-            if target.ends_with("windows-gnu") {
+            if target.is_windows_gnu() {
                 candle("GccGroup.wxs".as_ref());
             }
 
@@ -1949,7 +1933,7 @@ impl Step for Extended {
                 cmd.arg("DocsGroup.wixobj");
             }
 
-            if target.ends_with("windows-gnu") {
+            if target.is_windows_gnu() {
                 cmd.arg("GccGroup.wixobj");
             }
             // ICE57 wrongly complains about the shortcuts
@@ -1981,7 +1965,7 @@ fn add_env(builder: &Builder<'_>, cmd: &mut BootstrapCommand, target: TargetSele
 
     if target.contains("windows-gnullvm") {
         cmd.env("CFG_MINGW", "1").env("CFG_ABI", "LLVM");
-    } else if target.contains("windows-gnu") {
+    } else if target.is_windows_gnu() {
         cmd.env("CFG_MINGW", "1").env("CFG_ABI", "GNU");
     } else {
         cmd.env("CFG_MINGW", "0").env("CFG_ABI", "MSVC");
@@ -2095,7 +2079,7 @@ fn maybe_install_llvm(
 
 /// Maybe add libLLVM.so to the target lib-dir for linking.
 pub fn maybe_install_llvm_target(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path) {
-    let dst_libdir = sysroot.join("lib/rustlib").join(&*target.triple).join("lib");
+    let dst_libdir = sysroot.join("lib/rustlib").join(target).join("lib");
     // We do not need to copy LLVM files into the sysroot if it is not
     // dynamically linked; it is already included into librustc_llvm
     // statically.
@@ -2128,8 +2112,13 @@ impl Step for LlvmTools {
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
         let default = should_build_extended_tool(run.builder, "llvm-tools");
-        // FIXME: allow using the names of the tools themselves?
-        run.alias("llvm-tools").default_condition(default)
+
+        let mut run = run.alias("llvm-tools");
+        for tool in LLVM_TOOLS {
+            run = run.alias(tool);
+        }
+
+        run.default_condition(default)
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -2137,6 +2126,32 @@ impl Step for LlvmTools {
     }
 
     fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
+        fn tools_to_install(paths: &[PathBuf]) -> Vec<&'static str> {
+            let mut tools = vec![];
+
+            for path in paths {
+                let path = path.to_str().unwrap();
+
+                // Include all tools if path is 'llvm-tools'.
+                if path == "llvm-tools" {
+                    return LLVM_TOOLS.to_owned();
+                }
+
+                for tool in LLVM_TOOLS {
+                    if path == *tool {
+                        tools.push(*tool);
+                    }
+                }
+            }
+
+            // If no specific tool is requested, include all tools.
+            if tools.is_empty() {
+                tools = LLVM_TOOLS.to_owned();
+            }
+
+            tools
+        }
+
         let target = self.target;
 
         /* run only if llvm-config isn't used */
@@ -2157,7 +2172,7 @@ impl Step for LlvmTools {
             // Prepare the image directory
             let src_bindir = builder.llvm_out(target).join("bin");
             let dst_bindir = format!("lib/rustlib/{}/bin", target.triple);
-            for tool in LLVM_TOOLS {
+            for tool in tools_to_install(&builder.paths) {
                 let exe = src_bindir.join(exe(tool, target));
                 tarball.add_file(&exe, &dst_bindir, 0o755);
             }
diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs
index d8204ea00f7..301633559fe 100644
--- a/src/bootstrap/src/core/build_steps/doc.rs
+++ b/src/bootstrap/src/core/build_steps/doc.rs
@@ -9,14 +9,15 @@
 
 use std::io::{self, Write};
 use std::path::{Path, PathBuf};
-use std::{fs, mem};
+use std::{env, fs, mem};
 
 use crate::core::build_steps::compile;
 use crate::core::build_steps::tool::{self, prepare_tool_cargo, SourceType, Tool};
-use crate::core::builder::{self, crate_description};
-use crate::core::builder::{Alias, Builder, Compiler, Kind, RunConfig, ShouldRun, Step};
+use crate::core::builder::{
+    self, crate_description, Alias, Builder, Compiler, Kind, RunConfig, ShouldRun, Step,
+};
 use crate::core::config::{Config, TargetSelection};
-use crate::utils::helpers::{dir_is_empty, symlink_dir, t, up_to_date};
+use crate::utils::helpers::{symlink_dir, t, up_to_date};
 use crate::Mode;
 
 macro_rules! submodule_helper {
@@ -53,8 +54,8 @@ macro_rules! book {
 
             fn run(self, builder: &Builder<'_>) {
                 $(
-                    let path = Path::new(submodule_helper!( $path, submodule $( = $submodule )? ));
-                    builder.update_submodule(&path);
+                    let path = submodule_helper!( $path, submodule $( = $submodule )? );
+                    builder.require_submodule(path, None);
                 )?
                 builder.ensure(RustbookSrc {
                     target: self.target,
@@ -62,6 +63,7 @@ macro_rules! book {
                     src: builder.src.join($path),
                     parent: Some(self),
                     languages: $lang.into(),
+                    rustdoc: None,
                 })
             }
         }
@@ -80,7 +82,6 @@ book!(
     EditionGuide, "src/doc/edition-guide", "edition-guide", &[], submodule;
     EmbeddedBook, "src/doc/embedded-book", "embedded-book", &[], submodule;
     Nomicon, "src/doc/nomicon", "nomicon", &[], submodule;
-    Reference, "src/doc/reference", "reference", &[], submodule;
     RustByExample, "src/doc/rust-by-example", "rust-by-example", &["ja"], submodule;
     RustdocBook, "src/doc/rustdoc", "rustdoc", &[];
     StyleGuide, "src/doc/style-guide", "style-guide", &[];
@@ -112,6 +113,7 @@ impl Step for UnstableBook {
             src: builder.md_doc_out(self.target).join("unstable-book"),
             parent: Some(self),
             languages: vec![],
+            rustdoc: None,
         })
     }
 }
@@ -123,6 +125,7 @@ struct RustbookSrc<P: Step> {
     src: PathBuf,
     parent: Option<P>,
     languages: Vec<&'static str>,
+    rustdoc: Option<PathBuf>,
 }
 
 impl<P: Step> Step for RustbookSrc<P> {
@@ -153,13 +156,18 @@ impl<P: Step> Step for RustbookSrc<P> {
             builder.info(&format!("Rustbook ({target}) - {name}"));
             let _ = fs::remove_dir_all(&out);
 
-            builder
-                .tool_cmd(Tool::Rustbook)
-                .arg("build")
-                .arg(&src)
-                .arg("-d")
-                .arg(&out)
-                .run(builder);
+            let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook);
+            if let Some(mut rustdoc) = self.rustdoc {
+                rustdoc.pop();
+                let old_path = env::var_os("PATH").unwrap_or_default();
+                let new_path =
+                    env::join_paths(std::iter::once(rustdoc).chain(env::split_paths(&old_path)))
+                        .expect("could not add rustdoc to PATH");
+
+                rustbook_cmd.env("PATH", new_path);
+            }
+
+            rustbook_cmd.arg("build").arg(&src).arg("-d").arg(&out).run(builder);
 
             for lang in &self.languages {
                 let out = out.join(lang);
@@ -217,22 +225,14 @@ impl Step for TheBook {
     /// * Index page
     /// * Redirect pages
     fn run(self, builder: &Builder<'_>) {
-        let relative_path = Path::new("src").join("doc").join("book");
-        builder.update_submodule(&relative_path);
+        builder.require_submodule("src/doc/book", None);
 
         let compiler = self.compiler;
         let target = self.target;
 
-        let absolute_path = builder.src.join(&relative_path);
+        let absolute_path = builder.src.join("src/doc/book");
         let redirect_path = absolute_path.join("redirects");
-        if !absolute_path.exists()
-            || !redirect_path.exists()
-            || dir_is_empty(&absolute_path)
-            || dir_is_empty(&redirect_path)
-        {
-            eprintln!("Please checkout submodule: {}", relative_path.display());
-            crate::exit!(1);
-        }
+
         // build book
         builder.ensure(RustbookSrc {
             target,
@@ -240,6 +240,7 @@ impl Step for TheBook {
             src: absolute_path.clone(),
             parent: Some(self),
             languages: vec![],
+            rustdoc: None,
         });
 
         // building older edition redirects
@@ -252,6 +253,7 @@ impl Step for TheBook {
                 // treat the other editions as not having a parent.
                 parent: Option::<Self>::None,
                 languages: vec![],
+                rustdoc: None,
             });
         }
 
@@ -562,18 +564,8 @@ pub struct Std {
 }
 
 impl Std {
-    pub(crate) fn new(
-        stage: u32,
-        target: TargetSelection,
-        builder: &Builder<'_>,
-        format: DocumentationFormat,
-    ) -> Self {
-        let crates = builder
-            .in_tree_crates("sysroot", Some(target))
-            .into_iter()
-            .map(|krate| krate.name.to_string())
-            .collect();
-        Std { stage, target, format, crates }
+    pub(crate) fn new(stage: u32, target: TargetSelection, format: DocumentationFormat) -> Self {
+        Std { stage, target, format, crates: vec![] }
     }
 }
 
@@ -587,6 +579,7 @@ impl Step for Std {
     }
 
     fn make_run(run: RunConfig<'_>) {
+        let crates = compile::std_crates_for_run_make(&run);
         run.builder.ensure(Std {
             stage: run.builder.top_stage,
             target: run.target,
@@ -595,7 +588,7 @@ impl Step for Std {
             } else {
                 DocumentationFormat::Html
             },
-            crates: run.make_run_crates(Alias::Library),
+            crates,
         });
     }
 
@@ -606,6 +599,16 @@ impl Step for Std {
     fn run(self, builder: &Builder<'_>) {
         let stage = self.stage;
         let target = self.target;
+        let crates = if self.crates.is_empty() {
+            builder
+                .in_tree_crates("sysroot", Some(target))
+                .iter()
+                .map(|c| c.name.to_string())
+                .collect()
+        } else {
+            self.crates
+        };
+
         let out = match self.format {
             DocumentationFormat::Html => builder.doc_out(target),
             DocumentationFormat::Json => builder.json_doc_out(target),
@@ -634,7 +637,7 @@ impl Step for Std {
             extra_args.push("--disable-minification");
         }
 
-        doc_std(builder, self.format, stage, target, &out, &extra_args, &self.crates);
+        doc_std(builder, self.format, stage, target, &out, &extra_args, &crates);
 
         // Don't open if the format is json
         if let DocumentationFormat::Json = self.format {
@@ -646,7 +649,7 @@ impl Step for Std {
             let index = out.join("std").join("index.html");
             builder.open_in_browser(index);
         } else {
-            for requested_crate in &*self.crates {
+            for requested_crate in crates {
                 if STD_PUBLIC_CRATES.iter().any(|&k| k == requested_crate) {
                     let index = out.join(requested_crate).join("index.html");
                     builder.open_in_browser(index);
@@ -693,26 +696,18 @@ fn doc_std(
     extra_args: &[&str],
     requested_crates: &[String],
 ) {
-    if builder.no_std(target) == Some(true) {
-        panic!(
-            "building std documentation for no_std target {target} is not supported\n\
-             Set `docs = false` in the config to disable documentation, or pass `--skip library`."
-        );
-    }
-
     let compiler = builder.compiler(stage, builder.config.build);
 
     let target_doc_dir_name = if format == DocumentationFormat::Json { "json-doc" } else { "doc" };
-    let target_dir =
-        builder.stage_out(compiler, Mode::Std).join(target.triple).join(target_doc_dir_name);
+    let target_dir = builder.stage_out(compiler, Mode::Std).join(target).join(target_doc_dir_name);
 
     // This is directory where the compiler will place the output of the command.
     // We will then copy the files from this directory into the final `out` directory, the specified
     // as a function parameter.
-    let out_dir = target_dir.join(target.triple).join("doc");
+    let out_dir = target_dir.join(target).join("doc");
 
     let mut cargo =
-        builder::Cargo::new(builder, compiler, Mode::Std, SourceType::InTree, target, "doc");
+        builder::Cargo::new(builder, compiler, Mode::Std, SourceType::InTree, target, Kind::Doc);
 
     compile::std_cargo(builder, target, compiler.stage, &mut cargo);
     cargo
@@ -814,8 +809,14 @@ impl Step for Rustc {
         );
 
         // Build cargo command.
-        let mut cargo =
-            builder::Cargo::new(builder, compiler, Mode::Rustc, SourceType::InTree, target, "doc");
+        let mut cargo = builder::Cargo::new(
+            builder,
+            compiler,
+            Mode::Rustc,
+            SourceType::InTree,
+            target,
+            Kind::Doc,
+        );
 
         cargo.rustdocflag("--document-private-items");
         // Since we always pass --document-private-items, there's no need to warn about linking to private items.
@@ -844,7 +845,7 @@ impl Step for Rustc {
 
         let mut to_open = None;
 
-        let out_dir = builder.stage_out(compiler, Mode::Rustc).join(target.triple).join("doc");
+        let out_dir = builder.stage_out(compiler, Mode::Rustc).join(target).join("doc");
         for krate in &*self.crates {
             // Create all crate output directories first to make sure rustdoc uses
             // relative links.
@@ -932,8 +933,8 @@ macro_rules! tool_doc {
                     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 path = submodule_helper!( $path, submodule $( = $submodule )? );
+                    builder.require_submodule(path, None);
                 )?
 
                 let stage = builder.top_stage;
@@ -962,7 +963,7 @@ macro_rules! tool_doc {
                     compiler,
                     Mode::ToolRustc,
                     target,
-                    "doc",
+                    Kind::Doc,
                     $path,
                     source_type,
                     &[],
@@ -990,7 +991,7 @@ macro_rules! tool_doc {
                 // see https://github.com/rust-lang/rust/pull/122066#issuecomment-1983049222
                 // cargo.rustdocflag("--generate-link-to-definition");
 
-                let out_dir = builder.stage_out(compiler, Mode::ToolRustc).join(target.triple).join("doc");
+                let out_dir = builder.stage_out(compiler, Mode::ToolRustc).join(target).join("doc");
                 $(for krate in $crates {
                     let dir_name = krate.replace("-", "_");
                     t!(fs::create_dir_all(out_dir.join(&*dir_name)));
@@ -1172,12 +1173,6 @@ impl Step for RustcBook {
     /// in the "md-doc" directory in the build output directory. Then
     /// "rustbook" is used to convert it to HTML.
     fn run(self, builder: &Builder<'_>) {
-        // These submodules are required to be checked out to build rustbook
-        // because they have Cargo dependencies that are needed.
-        #[allow(clippy::single_element_loop)] // This will change soon.
-        for path in ["src/doc/book"] {
-            builder.update_submodule(Path::new(path));
-        }
         let out_base = builder.md_doc_out(self.target).join("rustc");
         t!(fs::create_dir_all(&out_base));
         let out_listing = out_base.join("src/lints");
@@ -1228,6 +1223,50 @@ impl Step for RustcBook {
             src: out_base,
             parent: Some(self),
             languages: vec![],
+            rustdoc: None,
+        });
+    }
+}
+
+#[derive(Ord, PartialOrd, Debug, Clone, Hash, PartialEq, Eq)]
+pub struct Reference {
+    pub compiler: Compiler,
+    pub target: TargetSelection,
+}
+
+impl Step for Reference {
+    type Output = ();
+    const DEFAULT: bool = true;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        let builder = run.builder;
+        run.path("src/doc/reference").default_condition(builder.config.docs)
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(Reference {
+            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
+            target: run.target,
+        });
+    }
+
+    /// Builds the reference book.
+    fn run(self, builder: &Builder<'_>) {
+        builder.require_submodule("src/doc/reference", None);
+
+        // This is needed for generating links to the standard library using
+        // the mdbook-spec plugin.
+        builder.ensure(compile::Std::new(self.compiler, builder.config.build));
+        let rustdoc = builder.rustdoc(self.compiler);
+
+        // Run rustbook/mdbook to generate the HTML pages.
+        builder.ensure(RustbookSrc {
+            target: self.target,
+            name: "reference".to_owned(),
+            src: builder.src.join("src/doc/reference"),
+            parent: Some(self),
+            languages: vec![],
+            rustdoc: Some(rustdoc),
         });
     }
 }
diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs
index f254c058b12..8c52df78ab6 100644
--- a/src/bootstrap/src/core/build_steps/format.rs
+++ b/src/bootstrap/src/core/build_steps/format.rs
@@ -1,17 +1,19 @@
 //! Runs rustfmt on the repository.
 
-use crate::core::builder::Builder;
-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;
 use std::sync::mpsc::SyncSender;
 use std::sync::Mutex;
 
+use build_helper::ci::CiEnv;
+use build_helper::git::get_git_modified_files;
+use ignore::WalkBuilder;
+
+use crate::core::builder::Builder;
+use crate::utils::exec::command;
+use crate::utils::helpers::{self, program_out_of_date, t};
+
 fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl FnMut(bool) -> bool {
     let mut cmd = Command::new(rustfmt);
     // Avoid the submodule config paths from coming into play. We only allow a single global config
diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs
index d3e9d6d7875..0ce86eadbce 100644
--- a/src/bootstrap/src/core/build_steps/install.rs
+++ b/src/bootstrap/src/core/build_steps/install.rs
@@ -3,9 +3,8 @@
 //! This module is responsible for installing the standard library,
 //! compiler, and documentation.
 
-use std::env;
-use std::fs;
 use std::path::{Component, Path, PathBuf};
+use std::{env, fs};
 
 use crate::core::build_steps::dist;
 use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index af987c59cb9..c5a1ab78801 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -8,25 +8,24 @@
 //! LLVM and compiler-rt are essentially just wired up to everything else to
 //! ensure that they're always in place if needed.
 
-use std::env;
 use std::env::consts::EXE_EXTENSION;
 use std::ffi::{OsStr, OsString};
 use std::fs::{self, File};
-use std::io;
 use std::path::{Path, PathBuf};
 use std::sync::OnceLock;
+use std::{env, io};
+
+use build_helper::ci::CiEnv;
 
 use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
 use crate::core::config::{Config, TargetSelection};
 use crate::utils::channel;
+use crate::utils::exec::command;
 use crate::utils::helpers::{
     self, exe, get_clang_cl_resource_dir, output, t, unhashed_basename, up_to_date,
 };
 use crate::{generate_smart_stamp_hash, CLang, GitRepo, Kind};
 
-use crate::utils::exec::command;
-use build_helper::ci::CiEnv;
-
 #[derive(Clone)]
 pub struct LlvmResult {
     /// Path to llvm-config binary.
@@ -89,7 +88,7 @@ impl LdFlags {
 /// if not).
 pub fn prebuilt_llvm_config(builder: &Builder<'_>, target: TargetSelection) -> LlvmBuildStatus {
     // If we have llvm submodule initialized already, sync it.
-    builder.update_existing_submodule(&Path::new("src").join("llvm-project"));
+    builder.update_existing_submodule("src/llvm-project");
 
     builder.config.maybe_download_ci_llvm();
 
@@ -110,7 +109,8 @@ pub fn prebuilt_llvm_config(builder: &Builder<'_>, target: TargetSelection) -> L
     }
 
     // Initialize the llvm submodule if not initialized already.
-    builder.update_submodule(&Path::new("src").join("llvm-project"));
+    // If submodules are disabled, this does nothing.
+    builder.update_submodule("src/llvm-project");
 
     let root = "src/llvm-project/llvm";
     let out_dir = builder.llvm_out(target);
@@ -194,6 +194,7 @@ pub(crate) fn is_ci_llvm_available(config: &Config, asserts: bool) -> bool {
     let supported_platforms = [
         // tier 1
         ("aarch64-unknown-linux-gnu", false),
+        ("aarch64-apple-darwin", false),
         ("i686-pc-windows-gnu", false),
         ("i686-pc-windows-msvc", false),
         ("i686-unknown-linux-gnu", false),
@@ -202,7 +203,6 @@ pub(crate) fn is_ci_llvm_available(config: &Config, asserts: bool) -> bool {
         ("x86_64-pc-windows-gnu", true),
         ("x86_64-pc-windows-msvc", true),
         // tier 2 with host tools
-        ("aarch64-apple-darwin", false),
         ("aarch64-pc-windows-msvc", false),
         ("aarch64-unknown-linux-musl", false),
         ("arm-unknown-linux-gnueabi", false),
@@ -368,9 +368,7 @@ impl Step for Llvm {
             cfg.define("LLVM_PROFDATA_FILE", path);
         }
 
-        // Disable zstd to avoid a dependency on libzstd.so.
-        cfg.define("LLVM_ENABLE_ZSTD", "OFF");
-
+        // Libraries for ELF section compression.
         if !target.is_windows() {
             cfg.define("LLVM_ENABLE_ZLIB", "ON");
         } else {
@@ -824,6 +822,14 @@ fn configure_llvm(builder: &Builder<'_>, target: TargetSelection, cfg: &mut cmak
         }
     }
 
+    // Libraries for ELF section compression.
+    if builder.config.llvm_libzstd {
+        cfg.define("LLVM_ENABLE_ZSTD", "FORCE_ON");
+        cfg.define("LLVM_USE_STATIC_ZSTD", "TRUE");
+    } else {
+        cfg.define("LLVM_ENABLE_ZSTD", "OFF");
+    }
+
     if let Some(ref linker) = builder.config.llvm_use_linker {
         cfg.define("LLVM_USE_LINKER", linker);
     }
@@ -1197,7 +1203,10 @@ impl Step for CrtBeginEnd {
 
     /// Build crtbegin.o/crtend.o for musl target.
     fn run(self, builder: &Builder<'_>) -> Self::Output {
-        builder.update_submodule(Path::new("src/llvm-project"));
+        builder.require_submodule(
+            "src/llvm-project",
+            Some("The LLVM sources are required for the CRT from `compiler-rt`."),
+        );
 
         let out_dir = builder.native_dir(self.target).join("crt");
 
@@ -1270,7 +1279,10 @@ impl Step for Libunwind {
 
     /// Build libunwind.a
     fn run(self, builder: &Builder<'_>) -> Self::Output {
-        builder.update_submodule(Path::new("src/llvm-project"));
+        builder.require_submodule(
+            "src/llvm-project",
+            Some("The LLVM sources are required for libunwind."),
+        );
 
         if builder.config.dry_run() {
             return PathBuf::new();
diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs
index b3ddb028015..65d635c0bd6 100644
--- a/src/bootstrap/src/core/build_steps/run.rs
+++ b/src/bootstrap/src/core/build_steps/run.rs
@@ -8,7 +8,7 @@ use std::path::PathBuf;
 use crate::core::build_steps::dist::distdir;
 use crate::core::build_steps::test;
 use crate::core::build_steps::tool::{self, SourceType, Tool};
-use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
+use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
 use crate::core::config::flags::get_completion;
 use crate::core::config::TargetSelection;
 use crate::utils::exec::command;
@@ -142,7 +142,7 @@ impl Step for Miri {
             host_compiler,
             Mode::ToolRustc,
             host,
-            "run",
+            Kind::Run,
             "src/tools/miri",
             SourceType::InTree,
             &[],
@@ -212,11 +212,13 @@ impl Step for GenerateCopyright {
         let license_metadata = builder.ensure(CollectLicenseMetadata);
 
         // Temporary location, it will be moved to the proper one once it's accurate.
-        let dest = builder.out.join("COPYRIGHT.md");
+        let dest = builder.out.join("COPYRIGHT.html");
 
         let mut cmd = builder.tool_cmd(Tool::GenerateCopyright);
         cmd.env("LICENSE_METADATA", &license_metadata);
         cmd.env("DEST", &dest);
+        cmd.env("OUT_DIR", &builder.out);
+        cmd.env("CARGO", &builder.initial_cargo);
         cmd.run(builder);
 
         dest
diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs
index 7da91b83895..8cd9ba5fd14 100644
--- a/src/bootstrap/src/core/build_steps/setup.rs
+++ b/src/bootstrap/src/core/build_steps/setup.rs
@@ -5,13 +5,6 @@
 //! allows setting up things that cannot be simply captured inside the config.toml, in addition to
 //! leading people away from manually editing most of the config.toml values.
 
-use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
-use crate::t;
-use crate::utils::change_tracker::CONFIG_CHANGE_HISTORY;
-use crate::utils::exec::command;
-use crate::utils::helpers::{self, hex_encode};
-use crate::Config;
-use sha2::Digest;
 use std::env::consts::EXE_SUFFIX;
 use std::fmt::Write as _;
 use std::fs::File;
@@ -20,6 +13,14 @@ use std::path::{Path, PathBuf, MAIN_SEPARATOR_STR};
 use std::str::FromStr;
 use std::{fmt, fs, io};
 
+use sha2::Digest;
+
+use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
+use crate::utils::change_tracker::CONFIG_CHANGE_HISTORY;
+use crate::utils::exec::command;
+use crate::utils::helpers::{self, hex_encode};
+use crate::{t, Config};
+
 #[cfg(test)]
 mod tests;
 
diff --git a/src/bootstrap/src/core/build_steps/setup/tests.rs b/src/bootstrap/src/core/build_steps/setup/tests.rs
index 3e4d66c7454..3552224f33b 100644
--- a/src/bootstrap/src/core/build_steps/setup/tests.rs
+++ b/src/bootstrap/src/core/build_steps/setup/tests.rs
@@ -1,6 +1,7 @@
+use sha2::Digest;
+
 use super::{RUST_ANALYZER_SETTINGS, SETTINGS_HASHES};
 use crate::utils::helpers::hex_encode;
-use sha2::Digest;
 
 #[test]
 fn check_matching_settings_hash() {
diff --git a/src/bootstrap/src/core/build_steps/suggest.rs b/src/bootstrap/src/core/build_steps/suggest.rs
index 0f4765fc121..8aaffab514d 100644
--- a/src/bootstrap/src/core/build_steps/suggest.rs
+++ b/src/bootstrap/src/core/build_steps/suggest.rs
@@ -2,10 +2,11 @@
 
 #![cfg_attr(feature = "build-metrics", allow(unused))]
 
-use clap::Parser;
 use std::path::PathBuf;
 use std::str::FromStr;
 
+use clap::Parser;
+
 use crate::core::build_steps::tool::Tool;
 use crate::core::builder::Builder;
 
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 9de92d41496..cc01afd4c18 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -3,27 +3,22 @@
 //! `./x.py test` (aka [`Kind::Test`]) is currently allowed to reach build steps in other modules.
 //! However, this contains ~all test parts we expect people to be able to build and run locally.
 
-use std::env;
-use std::ffi::OsStr;
-use std::ffi::OsString;
-use std::fs;
-use std::iter;
+use std::ffi::{OsStr, OsString};
 use std::path::{Path, PathBuf};
+use std::{env, fs, iter};
 
 use clap_complete::shells;
 
-use crate::core::build_steps::compile;
-use crate::core::build_steps::dist;
 use crate::core::build_steps::doc::DocumentationFormat;
-use crate::core::build_steps::llvm;
 use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget;
 use crate::core::build_steps::tool::{self, SourceType, Tool};
 use crate::core::build_steps::toolstate::ToolState;
+use crate::core::build_steps::{compile, dist, llvm};
 use crate::core::builder;
-use crate::core::builder::crate_description;
-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::builder::{
+    crate_description, Builder, Compiler, Kind, RunConfig, ShouldRun, Step,
+};
+use crate::core::config::flags::{get_completion, Subcommand};
 use crate::core::config::TargetSelection;
 use crate::utils::exec::{command, BootstrapCommand};
 use crate::utils::helpers::{
@@ -73,7 +68,7 @@ impl Step for CrateBootstrap {
             compiler,
             Mode::ToolBootstrap,
             bootstrap_host,
-            "test",
+            Kind::Test,
             path,
             SourceType::InTree,
             &[],
@@ -124,7 +119,7 @@ You can skip linkcheck with --skip src/tools/linkchecker"
             compiler,
             Mode::ToolBootstrap,
             bootstrap_host,
-            "test",
+            Kind::Test,
             "src/tools/linkchecker",
             SourceType::InTree,
             &[],
@@ -154,7 +149,7 @@ You can skip linkcheck with --skip src/tools/linkchecker"
         let _guard =
             builder.msg(Kind::Test, compiler.stage, "Linkcheck", bootstrap_host, bootstrap_host);
         let _time = helpers::timeit(builder);
-        linkchecker.delay_failure().arg(builder.out.join(host.triple).join("doc")).run(builder);
+        linkchecker.delay_failure().arg(builder.out.join(host).join("doc")).run(builder);
     }
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
@@ -289,7 +284,7 @@ impl Step for Cargo {
             compiler,
             Mode::ToolRustc,
             self.host,
-            "test",
+            Kind::Test,
             "src/tools/cargo",
             SourceType::Submodule,
             &[],
@@ -360,7 +355,7 @@ impl Step for RustAnalyzer {
             compiler,
             Mode::ToolRustc,
             host,
-            "test",
+            Kind::Test,
             crate_path,
             SourceType::InTree,
             &["in-rust-tree".to_owned()],
@@ -412,7 +407,7 @@ impl Step for Rustfmt {
             compiler,
             Mode::ToolRustc,
             host,
-            "test",
+            Kind::Test,
             "src/tools/rustfmt",
             SourceType::InTree,
             &[],
@@ -439,15 +434,15 @@ impl Miri {
         builder: &Builder<'_>,
         compiler: Compiler,
         target: TargetSelection,
-    ) -> String {
-        let miri_sysroot = builder.out.join(compiler.host.triple).join("miri-sysroot");
+    ) -> PathBuf {
+        let miri_sysroot = builder.out.join(compiler.host).join("miri-sysroot");
         let mut cargo = builder::Cargo::new(
             builder,
             compiler,
             Mode::Std,
             SourceType::Submodule,
             target,
-            "miri-setup",
+            Kind::MiriSetup,
         );
 
         // Tell `cargo miri setup` where to find the sources.
@@ -472,7 +467,7 @@ impl Miri {
         // Output is "<sysroot>\n".
         let sysroot = stdout.trim_end();
         builder.verbose(|| println!("`cargo miri setup --print-sysroot` said: {sysroot:?}"));
-        sysroot.to_owned()
+        PathBuf::from(sysroot)
     }
 }
 
@@ -525,6 +520,16 @@ impl Step for Miri {
         builder.ensure(compile::Std::new(target_compiler, host));
         let host_sysroot = builder.sysroot(target_compiler);
 
+        // Miri has its own "target dir" for ui test dependencies. Make sure it gets cleared when
+        // the sysroot gets rebuilt, to avoid "found possibly newer version of crate `std`" errors.
+        if !builder.config.dry_run() {
+            let ui_test_dep_dir = builder.stage_out(host_compiler, Mode::ToolStd).join("miri_ui");
+            // The mtime of `miri_sysroot` changes when the sysroot gets rebuilt (also see
+            // <https://github.com/RalfJung/rustc-build-sysroot/commit/10ebcf60b80fe2c3dc765af0ff19fdc0da4b7466>).
+            // We can hence use that directly as a signal to clear the ui test dir.
+            builder.clear_if_dirty(&ui_test_dep_dir, &miri_sysroot);
+        }
+
         // Run `cargo test`.
         // This is with the Miri crate, so it uses the host compiler.
         let mut cargo = tool::prepare_tool_cargo(
@@ -532,7 +537,7 @@ impl Step for Miri {
             host_compiler,
             Mode::ToolRustc,
             host,
-            "test",
+            Kind::Test,
             "src/tools/miri",
             SourceType::InTree,
             &[],
@@ -622,7 +627,7 @@ impl Step for CargoMiri {
             compiler,
             Mode::ToolStd, // it's unclear what to use here, we're not building anything just doing a smoke test!
             target,
-            "miri-test",
+            Kind::MiriTest,
             "src/tools/miri/test-cargo-miri",
             SourceType::Submodule,
             &[],
@@ -682,7 +687,7 @@ impl Step for CompiletestTest {
             // when std sources change.
             Mode::ToolStd,
             host,
-            "test",
+            Kind::Test,
             "src/tools/compiletest",
             SourceType::InTree,
             &[],
@@ -732,7 +737,7 @@ impl Step for Clippy {
             compiler,
             Mode::ToolRustc,
             host,
-            "test",
+            Kind::Test,
             "src/tools/clippy",
             SourceType::InTree,
             &[],
@@ -852,7 +857,6 @@ impl Step for RustdocJSStd {
         builder.ensure(crate::core::build_steps::doc::Std::new(
             builder.top_stage,
             self.target,
-            builder,
             DocumentationFormat::Html,
         ));
         let _guard = builder.msg(
@@ -1111,7 +1115,7 @@ HELP: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to
 }
 
 fn testdir(builder: &Builder<'_>, host: TargetSelection) -> PathBuf {
-    builder.out.join(host.triple).join("test")
+    builder.out.join(host).join("test")
 }
 
 macro_rules! default_test {
@@ -1282,7 +1286,7 @@ impl Step for RunMakeSupport {
             self.compiler,
             Mode::ToolStd,
             self.target,
-            "build",
+            Kind::Build,
             "src/tools/run-make-support",
             SourceType::InTree,
             &[],
@@ -1326,7 +1330,7 @@ impl Step for CrateRunMakeSupport {
             compiler,
             Mode::ToolBootstrap,
             host,
-            "test",
+            Kind::Test,
             "src/tools/run-make-support",
             SourceType::InTree,
             &[],
@@ -1372,7 +1376,7 @@ impl Step for CrateBuildHelper {
             compiler,
             Mode::ToolBootstrap,
             host,
-            "test",
+            Kind::Test,
             "src/tools/build_helper",
             SourceType::InTree,
             &[],
@@ -1813,7 +1817,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
 
         let mut flags = if is_rustdoc { Vec::new() } else { vec!["-Crpath".to_string()] };
         flags.push(format!("-Cdebuginfo={}", builder.config.rust_debuginfo_level_tests));
-        flags.extend(builder.config.cmd.rustc_args().iter().map(|s| s.to_string()));
+        flags.extend(builder.config.cmd.compiletest_rustc_args().iter().map(|s| s.to_string()));
 
         if suite != "mir-opt" {
             if let Some(linker) = builder.linker(target) {
@@ -2092,7 +2096,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
         let git_config = builder.config.git_config();
         cmd.arg("--git-repository").arg(git_config.git_repository);
         cmd.arg("--nightly-branch").arg(git_config.nightly_branch);
-        cmd.force_coloring_in_ci(builder.ci_env);
+        cmd.force_coloring_in_ci();
 
         #[cfg(feature = "build-metrics")]
         builder.metrics.begin_test_suite(
@@ -2254,7 +2258,12 @@ impl BookTest {
 }
 
 macro_rules! test_book {
-    ($($name:ident, $path:expr, $book_name:expr, default=$default:expr;)+) => {
+    ($(
+        $name:ident, $path:expr, $book_name:expr,
+        default=$default:expr
+        $(,submodules = $submodules:expr)?
+        ;
+    )+) => {
         $(
             #[derive(Debug, Clone, PartialEq, Eq, Hash)]
             pub struct $name {
@@ -2277,6 +2286,11 @@ macro_rules! test_book {
                 }
 
                 fn run(self, builder: &Builder<'_>) {
+                    $(
+                        for submodule in $submodules {
+                            builder.require_submodule(submodule, None);
+                        }
+                    )*
                     builder.ensure(BookTest {
                         compiler: self.compiler,
                         path: PathBuf::from($path),
@@ -2290,15 +2304,15 @@ macro_rules! test_book {
 }
 
 test_book!(
-    Nomicon, "src/doc/nomicon", "nomicon", default=false;
-    Reference, "src/doc/reference", "reference", default=false;
+    Nomicon, "src/doc/nomicon", "nomicon", default=false, submodules=["src/doc/nomicon"];
+    Reference, "src/doc/reference", "reference", default=false, submodules=["src/doc/reference"];
     RustdocBook, "src/doc/rustdoc", "rustdoc", default=true;
     RustcBook, "src/doc/rustc", "rustc", default=true;
-    RustByExample, "src/doc/rust-by-example", "rust-by-example", default=false;
-    EmbeddedBook, "src/doc/embedded-book", "embedded-book", default=false;
-    TheBook, "src/doc/book", "book", default=false;
+    RustByExample, "src/doc/rust-by-example", "rust-by-example", default=false, submodules=["src/doc/rust-by-example"];
+    EmbeddedBook, "src/doc/embedded-book", "embedded-book", default=false, submodules=["src/doc/embedded-book"];
+    TheBook, "src/doc/book", "book", default=false, submodules=["src/doc/book"];
     UnstableBook, "src/doc/unstable-book", "unstable-book", default=true;
-    EditionGuide, "src/doc/edition-guide", "edition-guide", default=false;
+    EditionGuide, "src/doc/edition-guide", "edition-guide", default=false, submodules=["src/doc/edition-guide"];
 );
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -2396,8 +2410,8 @@ impl Step for RustcGuide {
     }
 
     fn run(self, builder: &Builder<'_>) {
-        let relative_path = Path::new("src").join("doc").join("rustc-dev-guide");
-        builder.update_submodule(&relative_path);
+        let relative_path = "src/doc/rustc-dev-guide";
+        builder.require_submodule(relative_path, None);
 
         let src = builder.src.join(relative_path);
         let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook).delay_failure();
@@ -2626,7 +2640,7 @@ impl Step for Crate {
                 mode,
                 SourceType::InTree,
                 target,
-                "miri-test",
+                Kind::MiriTest,
             );
             // This hack helps bootstrap run standard library tests in Miri. The issue is as
             // follows: when running `cargo miri test` on libcore, cargo builds a local copy of core
@@ -2649,14 +2663,7 @@ impl Step for Crate {
             }
 
             // Build `cargo test` command
-            builder::Cargo::new(
-                builder,
-                compiler,
-                mode,
-                SourceType::InTree,
-                target,
-                builder.kind.as_str(),
-            )
+            builder::Cargo::new(builder, compiler, mode, SourceType::InTree, target, builder.kind)
         };
 
         match mode {
@@ -2678,7 +2685,7 @@ impl Step for Crate {
                     if builder.download_rustc() && compiler.stage > 0 {
                         let sysroot = builder
                             .out
-                            .join(compiler.host.triple)
+                            .join(compiler.host)
                             .join(format!("stage{}-test-sysroot", compiler.stage));
                         cargo.env("RUSTC_SYSROOT", sysroot);
                     }
@@ -2748,7 +2755,7 @@ impl Step for CrateRustdoc {
             compiler,
             Mode::ToolRustc,
             target,
-            builder.kind.as_str(),
+            builder.kind,
             "src/tools/rustdoc",
             SourceType::InTree,
             &[],
@@ -2840,7 +2847,7 @@ impl Step for CrateRustdocJsonTypes {
             compiler,
             Mode::ToolRustc,
             target,
-            builder.kind.as_str(),
+            builder.kind,
             "src/rustdoc-json-types",
             SourceType::InTree,
             &[],
@@ -3003,7 +3010,7 @@ impl Step for Bootstrap {
         let _guard = builder.msg(Kind::Test, 0, "bootstrap", host, host);
 
         // Some tests require cargo submodule to be present.
-        builder.build.update_submodule(Path::new("src/tools/cargo"));
+        builder.build.require_submodule("src/tools/cargo", None);
 
         let mut check_bootstrap = command(builder.python());
         check_bootstrap
@@ -3074,7 +3081,7 @@ impl Step for TierCheck {
             self.compiler,
             Mode::ToolStd,
             self.compiler.host,
-            "run",
+            Kind::Run,
             "src/tools/tier-check",
             SourceType::InTree,
             &[],
@@ -3146,7 +3153,7 @@ impl Step for RustInstaller {
             compiler,
             Mode::ToolBootstrap,
             bootstrap_host,
-            "test",
+            Kind::Test,
             "src/tools/rust-installer",
             SourceType::InTree,
             &[],
@@ -3316,7 +3323,7 @@ impl Step for CodegenCranelift {
                 Mode::Codegen, // Must be codegen to ensure dlopen on compiled dylibs works
                 SourceType::InTree,
                 target,
-                "run",
+                Kind::Run,
             );
 
             cargo.current_dir(&builder.src.join("compiler/rustc_codegen_cranelift"));
@@ -3448,7 +3455,7 @@ impl Step for CodegenGCC {
                 Mode::Codegen, // Must be codegen to ensure dlopen on compiled dylibs works
                 SourceType::InTree,
                 target,
-                "run",
+                Kind::Run,
             );
 
             cargo.current_dir(&builder.src.join("compiler/rustc_codegen_gcc"));
@@ -3536,7 +3543,7 @@ impl Step for TestFloatParse {
             compiler,
             Mode::ToolStd,
             bootstrap_host,
-            "test",
+            Kind::Test,
             path,
             SourceType::InTree,
             &[],
@@ -3559,7 +3566,7 @@ impl Step for TestFloatParse {
             compiler,
             Mode::ToolStd,
             bootstrap_host,
-            "run",
+            Kind::Run,
             path,
             SourceType::InTree,
             &[],
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index 06bb8259fc4..4d573b107b5 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -1,6 +1,5 @@
-use std::env;
-use std::fs;
-use std::path::{Path, PathBuf};
+use std::path::PathBuf;
+use std::{env, fs};
 
 use crate::core::build_steps::compile;
 use crate::core::build_steps::toolstate::ToolState;
@@ -10,9 +9,7 @@ use crate::core::config::TargetSelection;
 use crate::utils::channel::GitInfo;
 use crate::utils::exec::{command, BootstrapCommand};
 use crate::utils::helpers::{add_dylib_path, exe, get_closest_merge_base_commit, git, t};
-use crate::Compiler;
-use crate::Mode;
-use crate::{gha, Kind};
+use crate::{gha, Compiler, Kind, Mode};
 
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub enum SourceType {
@@ -93,7 +90,7 @@ impl Step for ToolBuild {
             compiler,
             self.mode,
             target,
-            "build",
+            Kind::Build,
             path,
             self.source_type,
             &self.extra_features,
@@ -139,12 +136,12 @@ pub fn prepare_tool_cargo(
     compiler: Compiler,
     mode: Mode,
     target: TargetSelection,
-    command: &'static str,
+    cmd_kind: Kind,
     path: &str,
     source_type: SourceType,
     extra_features: &[String],
 ) -> CargoCommand {
-    let mut cargo = builder::Cargo::new(builder, compiler, mode, source_type, target, command);
+    let mut cargo = builder::Cargo::new(builder, compiler, mode, source_type, target, cmd_kind);
 
     let dir = builder.src.join(path);
     cargo.arg("--manifest-path").arg(dir.join("Cargo.toml"));
@@ -241,6 +238,7 @@ macro_rules! bootstrap_tool {
         $(,is_external_tool = $external:expr)*
         $(,is_unstable_tool = $unstable:expr)*
         $(,allow_features = $allow_features:expr)?
+        $(,submodules = $submodules:expr)?
         ;
     )+) => {
         #[derive(PartialEq, Eq, Clone)]
@@ -287,6 +285,11 @@ macro_rules! bootstrap_tool {
             }
 
             fn run(self, builder: &Builder<'_>) -> PathBuf {
+                $(
+                    for submodule in $submodules {
+                        builder.require_submodule(submodule, None);
+                    }
+                )*
                 builder.ensure(ToolBuild {
                     compiler: self.compiler,
                     target: self.target,
@@ -314,7 +317,7 @@ macro_rules! bootstrap_tool {
 }
 
 bootstrap_tool!(
-    Rustbook, "src/tools/rustbook", "rustbook";
+    Rustbook, "src/tools/rustbook", "rustbook", submodules = SUBMODULES_FOR_RUSTBOOK;
     UnstableBookGen, "src/tools/unstable-book-gen", "unstable-book-gen";
     Tidy, "src/tools/tidy", "tidy";
     Linkchecker, "src/tools/linkchecker", "linkchecker";
@@ -340,6 +343,10 @@ bootstrap_tool!(
     WasmComponentLd, "src/tools/wasm-component-ld", "wasm-component-ld", is_unstable_tool = true, allow_features = "min_specialization";
 );
 
+/// These are the submodules that are required for rustbook to work due to
+/// depending on mdbook plugins.
+pub static SUBMODULES_FOR_RUSTBOOK: &[&str] = &["src/doc/book", "src/doc/reference"];
+
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct OptimizedDist {
     pub compiler: Compiler,
@@ -363,7 +370,7 @@ impl Step for OptimizedDist {
     fn run(self, builder: &Builder<'_>) -> PathBuf {
         // We need to ensure the rustc-perf submodule is initialized when building opt-dist since
         // the tool requires it to be in place to run.
-        builder.update_submodule(Path::new("src/tools/rustc-perf"));
+        builder.require_submodule("src/tools/rustc-perf", None);
 
         builder.ensure(ToolBuild {
             compiler: self.compiler,
@@ -404,7 +411,7 @@ impl Step for RustcPerf {
 
     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"));
+        builder.require_submodule("src/tools/rustc-perf", None);
 
         let tool = ToolBuild {
             compiler: self.compiler,
@@ -639,7 +646,7 @@ impl Step for Rustdoc {
             build_compiler,
             Mode::ToolRustc,
             target,
-            "build",
+            Kind::Build,
             "src/tools/rustdoc",
             SourceType::InTree,
             features.as_slice(),
@@ -704,7 +711,7 @@ impl Step for Cargo {
     }
 
     fn run(self, builder: &Builder<'_>) -> PathBuf {
-        builder.build.update_submodule(Path::new("src/tools/cargo"));
+        builder.build.require_submodule("src/tools/cargo", None);
 
         builder.ensure(ToolBuild {
             compiler: self.compiler,
@@ -898,7 +905,7 @@ impl Step for LlvmBitcodeLinker {
             self.compiler,
             Mode::ToolRustc,
             self.target,
-            "build",
+            Kind::Build,
             "src/tools/llvm-bitcode-linker",
             SourceType::InTree,
             &self.extra_features,
@@ -1086,8 +1093,6 @@ macro_rules! tool_extended {
 
 // NOTE: tools need to be also added to `Builder::get_step_descriptions` in `builder.rs`
 // to make `./x.py build <tool>` work.
-// NOTE: Most submodule updates for tools are handled by bootstrap.py, since they're needed just to
-// invoke Cargo to build bootstrap. See the comment there for more details.
 tool_extended!((self, builder),
     Cargofmt, "src/tools/rustfmt", "cargo-fmt", stable=true;
     CargoClippy, "src/tools/clippy", "cargo-clippy", stable=true;
diff --git a/src/bootstrap/src/core/build_steps/toolstate.rs b/src/bootstrap/src/core/build_steps/toolstate.rs
index 912cd4b8676..b73961062f6 100644
--- a/src/bootstrap/src/core/build_steps/toolstate.rs
+++ b/src/bootstrap/src/core/build_steps/toolstate.rs
@@ -4,16 +4,15 @@
 //!
 //! [Toolstate]: https://forge.rust-lang.org/infra/toolstate.html
 
-use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
-use crate::utils::helpers::{self, t};
-use serde_derive::{Deserialize, Serialize};
 use std::collections::HashMap;
-use std::env;
-use std::fmt;
-use std::fs;
 use std::io::{Seek, SeekFrom};
 use std::path::{Path, PathBuf};
-use std::time;
+use std::{env, fmt, fs, time};
+
+use serde_derive::{Deserialize, Serialize};
+
+use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
+use crate::utils::helpers::{self, t};
 
 // Each cycle is 42 days long (6 weeks); the last week is 35..=42 then.
 const BETA_WEEK_START: u64 = 35;
diff --git a/src/bootstrap/src/core/build_steps/vendor.rs b/src/bootstrap/src/core/build_steps/vendor.rs
index e6b3cb320cf..33768465225 100644
--- a/src/bootstrap/src/core/build_steps/vendor.rs
+++ b/src/bootstrap/src/core/build_steps/vendor.rs
@@ -1,6 +1,8 @@
+use std::path::PathBuf;
+
+use crate::core::build_steps::tool::SUBMODULES_FOR_RUSTBOOK;
 use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
 use crate::utils::exec::command;
-use std::path::{Path, PathBuf};
 
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub(crate) struct Vendor {
@@ -35,8 +37,8 @@ impl Step for Vendor {
         }
 
         // These submodules must be present for `x vendor` to work.
-        for path in ["src/tools/cargo", "src/doc/book"] {
-            builder.build.update_submodule(Path::new(path));
+        for submodule in SUBMODULES_FOR_RUSTBOOK.iter().chain(["src/tools/cargo"].iter()) {
+            builder.build.require_submodule(submodule, None);
         }
 
         // Sync these paths by default.
@@ -45,6 +47,7 @@ impl Step for Vendor {
             "src/tools/rust-analyzer/Cargo.toml",
             "compiler/rustc_codegen_cranelift/Cargo.toml",
             "compiler/rustc_codegen_gcc/Cargo.toml",
+            "library/Cargo.toml",
             "src/bootstrap/Cargo.toml",
             "src/tools/rustbook/Cargo.toml",
         ] {
diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs
index d21ddc5672b..454cc20d155 100644
--- a/src/bootstrap/src/core/builder.rs
+++ b/src/bootstrap/src/core/builder.rs
@@ -1,15 +1,16 @@
 use std::any::{type_name, Any};
 use std::cell::{Cell, RefCell};
 use std::collections::BTreeSet;
-use std::env;
 use std::ffi::{OsStr, OsString};
 use std::fmt::{Debug, Write};
-use std::fs;
 use std::hash::Hash;
 use std::ops::Deref;
 use std::path::{Path, PathBuf};
 use std::sync::LazyLock;
 use std::time::{Duration, Instant};
+use std::{env, fs};
+
+use clap::ValueEnum;
 
 use crate::core::build_steps::tool::{self, SourceType};
 use crate::core::build_steps::{
@@ -17,17 +18,16 @@ use crate::core::build_steps::{
 };
 use crate::core::config::flags::{Color, Subcommand};
 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, t, LldThreads};
-use crate::EXTRA_CHECK_CFGS;
-use crate::{Build, CLang, Crate, DocTests, GitRepo, Mode};
-
 use crate::utils::exec::{command, BootstrapCommand};
+use crate::utils::helpers::{
+    self, add_dylib_path, add_link_lib_path, check_cfg_arg, exe, libdir, linker_args, linker_flags,
+    t, LldThreads,
+};
 pub use crate::Compiler;
-
-use clap::ValueEnum;
+use crate::{
+    prepare_behaviour_dump_dir, Build, CLang, Crate, DocTests, GitRepo, Mode, EXTRA_CHECK_CFGS,
+};
 
 #[cfg(test)]
 mod tests;
@@ -689,7 +689,7 @@ impl<'a> ShouldRun<'a> {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
+#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq, PartialOrd, Ord, ValueEnum)]
 pub enum Kind {
     #[value(alias = "b")]
     Build,
@@ -701,6 +701,8 @@ pub enum Kind {
     #[value(alias = "t")]
     Test,
     Miri,
+    MiriSetup,
+    MiriTest,
     Bench,
     #[value(alias = "d")]
     Doc,
@@ -725,6 +727,8 @@ impl Kind {
             Kind::Format => "fmt",
             Kind::Test => "test",
             Kind::Miri => "miri",
+            Kind::MiriSetup => panic!("`as_str` is not supported for `Kind::MiriSetup`."),
+            Kind::MiriTest => panic!("`as_str` is not supported for `Kind::MiriTest`."),
             Kind::Bench => "bench",
             Kind::Doc => "doc",
             Kind::Clean => "clean",
@@ -1000,6 +1004,7 @@ impl<'a> Builder<'a> {
             Kind::Vendor => describe!(vendor::Vendor),
             // special-cased in Build::build()
             Kind::Format | Kind::Suggest | Kind::Perf => vec![],
+            Kind::MiriTest | Kind::MiriSetup => unreachable!(),
         }
     }
 
@@ -1101,6 +1106,12 @@ impl<'a> Builder<'a> {
         StepDescription::run(v, self, paths);
     }
 
+    /// Returns if `std` should be statically linked into `rustc_driver`.
+    /// It's currently not done on `windows-gnu` due to linker bugs.
+    pub fn link_std_into_rustc_driver(&self, target: TargetSelection) -> bool {
+        !target.triple.ends_with("-windows-gnu")
+    }
+
     /// Obtain a compiler at a given stage and for a given host (i.e., this is the target that the
     /// compiler will run on, *not* the target it will build code for). Explicitly does not take
     /// `Compiler` since all `Compiler` instances are meant to be obtained through this function,
@@ -1160,7 +1171,7 @@ impl<'a> Builder<'a> {
                     .sysroot(self.compiler)
                     .join(lib)
                     .join("rustlib")
-                    .join(self.target.triple)
+                    .join(self.target)
                     .join("lib");
                 // Avoid deleting the rustlib/ directory we just copied
                 // (in `impl Step for Sysroot`).
@@ -1243,7 +1254,7 @@ impl<'a> Builder<'a> {
 
         // Ensure that the downloaded LLVM libraries can be found.
         if self.config.llvm_from_ci {
-            let ci_llvm_lib = self.out.join(&*compiler.host.triple).join("ci-llvm").join("lib");
+            let ci_llvm_lib = self.out.join(compiler.host).join("ci-llvm").join("lib");
             dylib_dirs.push(ci_llvm_lib);
         }
 
@@ -1386,23 +1397,30 @@ impl<'a> Builder<'a> {
         compiler: Compiler,
         mode: Mode,
         target: TargetSelection,
-        cmd: &str, // FIXME make this properly typed
+        cmd_kind: Kind,
     ) -> BootstrapCommand {
-        let mut cargo;
-        if cmd == "clippy" {
-            cargo = self.cargo_clippy_cmd(compiler);
-            cargo.arg(cmd);
-        } else if let Some(subcmd) = cmd.strip_prefix("miri") {
-            // Command must be "miri-X".
-            let subcmd = subcmd
-                .strip_prefix('-')
-                .unwrap_or_else(|| panic!("expected `miri-$subcommand`, but got {}", cmd));
-            cargo = self.cargo_miri_cmd(compiler);
-            cargo.arg("miri").arg(subcmd);
-        } else {
-            cargo = command(&self.initial_cargo);
-            cargo.arg(cmd);
-        }
+        let mut cargo = match cmd_kind {
+            Kind::Clippy => {
+                let mut cargo = self.cargo_clippy_cmd(compiler);
+                cargo.arg(cmd_kind.as_str());
+                cargo
+            }
+            Kind::MiriSetup => {
+                let mut cargo = self.cargo_miri_cmd(compiler);
+                cargo.arg("miri").arg("setup");
+                cargo
+            }
+            Kind::MiriTest => {
+                let mut cargo = self.cargo_miri_cmd(compiler);
+                cargo.arg("miri").arg("test");
+                cargo
+            }
+            _ => {
+                let mut cargo = command(&self.initial_cargo);
+                cargo.arg(cmd_kind.as_str());
+                cargo
+            }
+        };
 
         // Run cargo from the source root so it can find .cargo/config.
         // This matters when using vendoring and the working directory is outside the repository.
@@ -1431,7 +1449,7 @@ impl<'a> Builder<'a> {
             Color::Auto => {} // nothing to do
         }
 
-        if cmd != "install" {
+        if cmd_kind != Kind::Install {
             cargo.arg("--target").arg(target.rustc_target_arg());
         } else {
             assert_eq!(target, compiler.host);
@@ -1440,8 +1458,11 @@ impl<'a> Builder<'a> {
         if self.config.rust_optimize.is_release() {
             // FIXME: cargo bench/install do not accept `--release`
             // and miri doesn't want it
-            if cmd != "bench" && cmd != "install" && !cmd.starts_with("miri-") {
-                cargo.arg("--release");
+            match cmd_kind {
+                Kind::Bench | Kind::Install | Kind::Miri | Kind::MiriSetup | Kind::MiriTest => {}
+                _ => {
+                    cargo.arg("--release");
+                }
             }
         }
 
@@ -1464,9 +1485,9 @@ impl<'a> Builder<'a> {
         mode: Mode,
         source_type: SourceType,
         target: TargetSelection,
-        cmd: &str, // FIXME make this properly typed
+        cmd_kind: Kind,
     ) -> Cargo {
-        let mut cargo = self.bare_cargo(compiler, mode, target, cmd);
+        let mut cargo = self.bare_cargo(compiler, mode, target, cmd_kind);
         let out_dir = self.stage_out(compiler, mode);
 
         let mut hostflags = HostFlags::default();
@@ -1477,15 +1498,15 @@ impl<'a> Builder<'a> {
             self.clear_if_dirty(&out_dir, &backend);
         }
 
-        if cmd == "doc" || cmd == "rustdoc" {
+        if cmd_kind == Kind::Doc {
             let my_out = match mode {
                 // This is the intended out directory for compiler documentation.
                 Mode::Rustc | Mode::ToolRustc => self.compiler_doc_out(target),
                 Mode::Std => {
                     if self.config.cmd.json() {
-                        out_dir.join(target.triple).join("json-doc")
+                        out_dir.join(target).join("json-doc")
                     } else {
-                        out_dir.join(target.triple).join("doc")
+                        out_dir.join(target).join("doc")
                     }
                 }
                 _ => panic!("doc mode {mode:?} not expected"),
@@ -1508,7 +1529,7 @@ impl<'a> Builder<'a> {
 
         // Set a flag for `check`/`clippy`/`fix`, so that certain build
         // scripts can do less work (i.e. not building/requiring LLVM).
-        if cmd == "check" || cmd == "clippy" || cmd == "fix" {
+        if matches!(cmd_kind, Kind::Check | Kind::Clippy | Kind::Fix) {
             // If we've not yet built LLVM, or it's stale, then bust
             // the rustc_llvm cache. That will always work, even though it
             // may mean that on the next non-check build we'll need to rebuild
@@ -1558,7 +1579,7 @@ impl<'a> Builder<'a> {
             rustflags.arg("--cfg=bootstrap");
         }
 
-        if cmd == "clippy" {
+        if cmd_kind == Kind::Clippy {
             // clippy overwrites sysroot if we pass it to cargo.
             // Pass it directly to clippy instead.
             // NOTE: this can't be fixed in clippy because we explicitly don't set `RUSTC`,
@@ -1654,7 +1675,7 @@ impl<'a> Builder<'a> {
             Mode::Std | Mode::ToolBootstrap | Mode::ToolStd => {}
             Mode::Rustc | Mode::Codegen | Mode::ToolRustc => {
                 // Build proc macros both for the host and the target
-                if target != compiler.host && cmd != "check" {
+                if target != compiler.host && cmd_kind != Kind::Check {
                     cargo.arg("-Zdual-proc-macros");
                     rustflags.arg("-Zdual-proc-macros");
                 }
@@ -1739,7 +1760,7 @@ impl<'a> Builder<'a> {
         }
         cargo.env("__CARGO_DEFAULT_LIB_METADATA", &metadata);
 
-        if cmd == "clippy" {
+        if cmd_kind == Kind::Clippy {
             rustflags.arg("-Zforce-unstable-if-unmarked");
         }
 
@@ -1755,10 +1776,15 @@ impl<'a> Builder<'a> {
         //
         // Only clear out the directory if we're compiling std; otherwise, we
         // should let Cargo take care of things for us (via depdep info)
-        if !self.config.dry_run() && mode == Mode::Std && cmd == "build" {
+        if !self.config.dry_run() && mode == Mode::Std && cmd_kind == Kind::Build {
             self.clear_if_dirty(&out_dir, &self.rustc(compiler));
         }
 
+        let rustdoc_path = match cmd_kind {
+            Kind::Doc | Kind::Test | Kind::MiriTest => self.rustdoc(compiler),
+            _ => PathBuf::from("/path/to/nowhere/rustdoc/not/required"),
+        };
+
         // Customize the compiler we're running. Specify the compiler to cargo
         // as our shim and then pass it some various options used to configure
         // how the actual compiler itself is called.
@@ -1772,15 +1798,7 @@ impl<'a> Builder<'a> {
             .env("RUSTC_SYSROOT", sysroot)
             .env("RUSTC_LIBDIR", libdir)
             .env("RUSTDOC", self.bootstrap_out.join("rustdoc"))
-            .env(
-                "RUSTDOC_REAL",
-                // Make sure to handle both `test` and `miri-test` commands.
-                if cmd == "doc" || cmd == "rustdoc" || (cmd.ends_with("test") && want_rustdoc) {
-                    self.rustdoc(compiler)
-                } else {
-                    PathBuf::from("/path/to/nowhere/rustdoc/not/required")
-                },
-            )
+            .env("RUSTDOC_REAL", rustdoc_path)
             .env("RUSTC_ERROR_METADATA_DST", self.extended_error_dir())
             .env("RUSTC_BREAK_ON_ICE", "1");
 
@@ -1799,7 +1817,7 @@ impl<'a> Builder<'a> {
         }
 
         // If this is for `miri-test`, prepare the sysroots.
-        if cmd == "miri-test" {
+        if cmd_kind == Kind::MiriTest {
             self.ensure(compile::Std::new(compiler, compiler.host));
             let host_sysroot = self.sysroot(compiler);
             let miri_sysroot = test::Miri::build_miri_sysroot(self, compiler, target);
@@ -1813,7 +1831,8 @@ impl<'a> Builder<'a> {
             rustflags.arg(&format!("-Zstack-protector={stack_protector}"));
         }
 
-        if !(["build", "check", "clippy", "fix", "rustc"].contains(&cmd)) && want_rustdoc {
+        if !matches!(cmd_kind, Kind::Build | Kind::Check | Kind::Clippy | Kind::Fix) && want_rustdoc
+        {
             cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(compiler));
         }
 
@@ -2144,15 +2163,23 @@ 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());
 
-        cargo.force_coloring_in_ci(self.ci_env);
+        cargo.force_coloring_in_ci();
 
         // When we build Rust dylibs they're all intended for intermediate
         // usage, so make sure we pass the -Cprefer-dynamic flag instead of
         // linking all deps statically into the dylib.
-        if matches!(mode, Mode::Std | Mode::Rustc) {
+        if matches!(mode, Mode::Std) {
+            rustflags.arg("-Cprefer-dynamic");
+        }
+        if matches!(mode, Mode::Rustc) && !self.link_std_into_rustc_driver(target) {
             rustflags.arg("-Cprefer-dynamic");
         }
 
+        cargo.env(
+            "RUSTC_LINK_STD_INTO_RUSTC_DRIVER",
+            if self.link_std_into_rustc_driver(target) { "1" } else { "0" },
+        );
+
         // When building incrementally we default to a lower ThinLTO import limit
         // (unless explicitly specified otherwise). This will produce a somewhat
         // slower code but give way better compile times.
@@ -2199,11 +2226,6 @@ impl<'a> Builder<'a> {
             rustdocflags.arg("--cfg=parallel_compiler");
         }
 
-        // Pass the value of `--rustc-args` from test command. If it's not a test command, this won't set anything.
-        self.config.cmd.rustc_args().iter().for_each(|v| {
-            rustflags.arg(v);
-        });
-
         Cargo {
             command: cargo,
             compiler,
@@ -2430,9 +2452,9 @@ impl Cargo {
         mode: Mode,
         source_type: SourceType,
         target: TargetSelection,
-        cmd: &str, // FIXME make this properly typed
+        cmd_kind: Kind,
     ) -> Cargo {
-        let mut cargo = builder.cargo(compiler, mode, source_type, target, cmd);
+        let mut cargo = builder.cargo(compiler, mode, source_type, target, cmd_kind);
         cargo.configure_linker(builder);
         cargo
     }
@@ -2448,9 +2470,9 @@ impl Cargo {
         mode: Mode,
         source_type: SourceType,
         target: TargetSelection,
-        cmd: &str, // FIXME make this properly typed
+        cmd_kind: Kind,
     ) -> Cargo {
-        builder.cargo(compiler, mode, source_type, target, cmd)
+        builder.cargo(compiler, mode, source_type, target, cmd_kind)
     }
 
     pub fn rustdocflag(&mut self, arg: &str) -> &mut Cargo {
diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs
index 97c9ece0036..c554684d5a7 100644
--- a/src/bootstrap/src/core/builder/tests.rs
+++ b/src/bootstrap/src/core/builder/tests.rs
@@ -1,27 +1,32 @@
+use std::thread;
+
 use super::*;
 use crate::core::build_steps::doc::DocumentationFormat;
 use crate::core::config::Config;
-use std::thread;
+use crate::Flags;
 
 fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config {
     configure_with_args(&[cmd.to_owned()], host, target)
 }
 
 fn configure_with_args(cmd: &[String], host: &[&str], target: &[&str]) -> Config {
-    let mut config = Config::parse(cmd);
+    let mut config = Config::parse(Flags::parse(cmd));
     // don't save toolstates
     config.save_toolstates = None;
     config.dry_run = DryRun::SelfCheck;
 
-    // Ignore most submodules, since we don't need them for a dry run.
-    // But make sure to check out the `doc` and `rust-analyzer` submodules, since some steps need them
-    // just to know which commands to run.
+    // Ignore most submodules, since we don't need them for a dry run, and the
+    // tests run much faster without them.
+    //
+    // The src/doc/book submodule is needed because TheBook step tries to
+    // access files even during a dry-run (may want to consider just skipping
+    // that in a dry run).
     let submodule_build = Build::new(Config {
         // don't include LLVM, so CI doesn't require ninja/cmake to be installed
         rust_codegen_backends: vec![],
-        ..Config::parse(&["check".to_owned()])
+        ..Config::parse(Flags::parse(&["check".to_owned()]))
     });
-    submodule_build.update_submodule(Path::new("src/doc/book"));
+    submodule_build.require_submodule("src/doc/book", None);
     config.submodules = Some(false);
 
     config.ninja_in_file = false;
@@ -75,13 +80,9 @@ macro_rules! std {
 
 macro_rules! doc_std {
     ($host:ident => $target:ident, stage = $stage:literal) => {{
-        let config = configure("doc", &["A-A"], &["A-A"]);
-        let build = Build::new(config);
-        let builder = Builder::new(&build);
         doc::Std::new(
             $stage,
             TargetSelection::from_user(concat!(stringify!($target), "-", stringify!($target))),
-            &builder,
             DocumentationFormat::Html,
         )
     }};
@@ -212,10 +213,11 @@ fn alias_and_path_for_library() {
 }
 
 mod defaults {
+    use pretty_assertions::assert_eq;
+
     use super::{configure, first, run_build};
     use crate::core::builder::*;
     use crate::Config;
-    use pretty_assertions::assert_eq;
 
     #[test]
     fn build_default() {
@@ -323,9 +325,10 @@ mod defaults {
 }
 
 mod dist {
+    use pretty_assertions::assert_eq;
+
     use super::{first, run_build, Config};
     use crate::core::builder::*;
-    use pretty_assertions::assert_eq;
 
     fn configure(host: &[&str], target: &[&str]) -> Config {
         Config { stage: 2, ..super::configure("dist", host, target) }
@@ -630,7 +633,7 @@ mod dist {
         config.paths = vec!["library/std".into()];
         config.cmd = Subcommand::Test {
             test_args: vec![],
-            rustc_args: vec![],
+            compiletest_rustc_args: vec![],
             no_fail_fast: false,
             no_doc: true,
             doc: false,
@@ -701,7 +704,7 @@ mod dist {
         let mut config = configure(&["A-A"], &["A-A"]);
         config.cmd = Subcommand::Test {
             test_args: vec![],
-            rustc_args: vec![],
+            compiletest_rustc_args: vec![],
             no_fail_fast: false,
             doc: true,
             no_doc: false,
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index e32288e2caf..36de8324f67 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -4,29 +4,27 @@
 //! how the build runs.
 
 use std::cell::{Cell, RefCell};
-use std::cmp;
 use std::collections::{HashMap, HashSet};
-use std::env;
 use std::fmt::{self, Display};
-use std::fs;
 use std::io::IsTerminal;
 use std::path::{absolute, Path, PathBuf};
 use std::process::Command;
 use std::str::FromStr;
 use std::sync::OnceLock;
+use std::{cmp, env, fs};
+
+use build_helper::exit;
+use build_helper::git::GitConfig;
+use serde::{Deserialize, Deserializer};
+use serde_derive::Deserialize;
 
 use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX;
 use crate::core::build_steps::llvm;
+pub use crate::core::config::flags::Subcommand;
 use crate::core::config::flags::{Color, Flags, Warnings};
 use crate::utils::cache::{Interned, INTERNER};
 use crate::utils::channel::{self, GitInfo};
 use crate::utils::helpers::{self, exe, get_closest_merge_base_commit, output, t};
-use build_helper::exit;
-use serde::{Deserialize, Deserializer};
-use serde_derive::Deserialize;
-
-pub use crate::core::config::flags::Subcommand;
-use build_helper::git::GitConfig;
 
 macro_rules! check_ci_llvm {
     ($name:expr) => {
@@ -220,6 +218,7 @@ pub struct Config {
     pub llvm_thin_lto: bool,
     pub llvm_release_debuginfo: bool,
     pub llvm_static_stdcpp: bool,
+    pub llvm_libzstd: bool,
     /// `None` if `llvm_from_ci` is true and we haven't yet downloaded llvm.
     #[cfg(not(test))]
     llvm_link_shared: Cell<Option<bool>>,
@@ -514,6 +513,15 @@ impl TargetSelection {
     pub fn is_windows(&self) -> bool {
         self.contains("windows")
     }
+
+    pub fn is_windows_gnu(&self) -> bool {
+        self.ends_with("windows-gnu")
+    }
+
+    /// Path to the file defining the custom target, if any.
+    pub fn filepath(&self) -> Option<&Path> {
+        self.file.as_ref().map(Path::new)
+    }
 }
 
 impl fmt::Display for TargetSelection {
@@ -538,6 +546,14 @@ impl PartialEq<&str> for TargetSelection {
     }
 }
 
+// Targets are often used as directory names throughout bootstrap.
+// This impl makes it more ergonomics to use them as such.
+impl AsRef<Path> for TargetSelection {
+    fn as_ref(&self) -> &Path {
+        self.triple.as_ref()
+    }
+}
+
 /// Per-target configuration stored in the global configuration structure.
 #[derive(Debug, Default, Clone, PartialEq, Eq)]
 pub struct Target {
@@ -875,6 +891,7 @@ define_config! {
         plugins: Option<bool> = "plugins",
         ccache: Option<StringOrBool> = "ccache",
         static_libstdcpp: Option<bool> = "static-libstdcpp",
+        libzstd: Option<bool> = "libzstd",
         ninja: Option<bool> = "ninja",
         targets: Option<String> = "targets",
         experimental_targets: Option<String> = "experimental-targets",
@@ -1150,6 +1167,7 @@ impl Config {
             llvm_optimize: true,
             ninja_in_file: true,
             llvm_static_stdcpp: false,
+            llvm_libzstd: false,
             backtrace: true,
             rust_optimize: RustOptimize::Bool(true),
             rust_optimize_tests: true,
@@ -1185,7 +1203,7 @@ impl Config {
         }
     }
 
-    pub fn parse(args: &[String]) -> Config {
+    pub fn parse(flags: Flags) -> Config {
         #[cfg(test)]
         fn get_toml(_: &Path) -> TomlConfig {
             TomlConfig::default()
@@ -1215,11 +1233,10 @@ impl Config {
                     exit!(2);
                 })
         }
-        Self::parse_inner(args, get_toml)
+        Self::parse_inner(flags, get_toml)
     }
 
-    pub(crate) fn parse_inner(args: &[String], get_toml: impl Fn(&Path) -> TomlConfig) -> Config {
-        let mut flags = Flags::parse(args);
+    pub(crate) fn parse_inner(mut flags: Flags, get_toml: impl Fn(&Path) -> TomlConfig) -> Config {
         let mut config = Config::default_opts();
 
         // Set flags.
@@ -1322,7 +1339,11 @@ impl Config {
         // Give a hard error if `--config` or `RUST_BOOTSTRAP_CONFIG` are set to a missing path,
         // but not if `config.toml` hasn't been created.
         let mut toml = if !using_default_path || toml_path.exists() {
-            config.config = Some(toml_path.clone());
+            config.config = Some(if cfg!(not(feature = "bootstrap-self-test")) {
+                toml_path.canonicalize().unwrap()
+            } else {
+                toml_path.clone()
+            });
             get_toml(&toml_path)
         } else {
             config.config = None;
@@ -1460,7 +1481,7 @@ impl Config {
             config.download_beta_toolchain();
             config
                 .out
-                .join(config.build.triple)
+                .join(config.build)
                 .join("stage0")
                 .join("bin")
                 .join(exe("rustc", config.build))
@@ -1475,7 +1496,7 @@ impl Config {
             config.download_beta_toolchain();
             config
                 .out
-                .join(config.build.triple)
+                .join(config.build)
                 .join("stage0")
                 .join("bin")
                 .join(exe("cargo", config.build))
@@ -1784,6 +1805,7 @@ impl Config {
                 plugins,
                 ccache,
                 static_libstdcpp,
+                libzstd,
                 ninja,
                 targets,
                 experimental_targets,
@@ -1818,6 +1840,7 @@ impl Config {
             set(&mut config.llvm_thin_lto, thin_lto);
             set(&mut config.llvm_release_debuginfo, release_debuginfo);
             set(&mut config.llvm_static_stdcpp, static_libstdcpp);
+            set(&mut config.llvm_libzstd, libzstd);
             if let Some(v) = link_shared {
                 config.llvm_link_shared.set(Some(v));
             }
@@ -1842,6 +1865,23 @@ impl Config {
             config.llvm_from_ci = config.parse_download_ci_llvm(download_ci_llvm, asserts);
 
             if config.llvm_from_ci {
+                let warn = |option: &str| {
+                    println!(
+                        "WARNING: `{option}` will only be used on `compiler/rustc_llvm` build, not for the LLVM build."
+                    );
+                    println!(
+                        "HELP: To use `{option}` for LLVM builds, set `download-ci-llvm` option to false."
+                    );
+                };
+
+                if static_libstdcpp.is_some() {
+                    warn("static-libstdcpp");
+                }
+
+                if link_shared.is_some() {
+                    warn("link-shared");
+                }
+
                 // None of the LLVM options, except assertions, are supported
                 // when using downloaded LLVM. We could just ignore these but
                 // that's potentially confusing, so force them to not be
@@ -1851,9 +1891,7 @@ impl Config {
                 check_ci_llvm!(optimize_toml);
                 check_ci_llvm!(thin_lto);
                 check_ci_llvm!(release_debuginfo);
-                // CI-built LLVM can be either dynamic or static. We won't know until we download it.
-                check_ci_llvm!(link_shared);
-                check_ci_llvm!(static_libstdcpp);
+                check_ci_llvm!(libzstd);
                 check_ci_llvm!(targets);
                 check_ci_llvm!(experimental_targets);
                 check_ci_llvm!(clang_cl);
@@ -2094,7 +2132,7 @@ impl Config {
 
         // CI should always run stage 2 builds, unless it specifically states otherwise
         #[cfg(not(test))]
-        if flags.stage.is_none() && crate::CiEnv::current() != crate::CiEnv::None {
+        if flags.stage.is_none() && build_helper::ci::CiEnv::is_ci() {
             match config.cmd {
                 Subcommand::Test { .. }
                 | Subcommand::Miri { .. }
@@ -2251,13 +2289,13 @@ impl Config {
     /// The absolute path to the downloaded LLVM artifacts.
     pub(crate) fn ci_llvm_root(&self) -> PathBuf {
         assert!(self.llvm_from_ci);
-        self.out.join(&*self.build.triple).join("ci-llvm")
+        self.out.join(self.build).join("ci-llvm")
     }
 
     /// Directory where the extracted `rustc-dev` component is stored.
     pub(crate) fn ci_rustc_dir(&self) -> PathBuf {
         assert!(self.download_rustc());
-        self.out.join(self.build.triple).join("ci-rustc")
+        self.out.join(self.build).join("ci-rustc")
     }
 
     /// Determine whether llvm should be linked dynamically.
@@ -2404,8 +2442,11 @@ impl Config {
             .unwrap_or_else(|| SplitDebuginfo::default_for_platform(target))
     }
 
-    pub fn submodules(&self, rust_info: &GitInfo) -> bool {
-        self.submodules.unwrap_or(rust_info.is_managed_git_subrepository())
+    /// Returns whether or not submodules should be managed by bootstrap.
+    pub fn submodules(&self) -> bool {
+        // If not specified in config, the default is to only manage
+        // submodules if we're currently inside a git repository.
+        self.submodules.unwrap_or(self.rust_info.is_managed_git_subrepository())
     }
 
     pub fn codegen_backends(&self, target: TargetSelection) -> &[String] {
diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs
index 19f752da81c..c3f17402814 100644
--- a/src/bootstrap/src/core/config/flags.rs
+++ b/src/bootstrap/src/core/config/flags.rs
@@ -183,9 +183,9 @@ pub struct Flags {
 }
 
 impl Flags {
-    pub fn parse(args: &[String]) -> Self {
-        let first = String::from("x.py");
-        let it = std::iter::once(&first).chain(args.iter());
+    /// Check if `<cmd> -h -v` was passed.
+    /// If yes, print the available paths and return `true`.
+    pub fn try_parse_verbose_help(args: &[String]) -> bool {
         // We need to check for `<cmd> -h -v`, in which case we list the paths
         #[derive(Parser)]
         #[command(disable_help_flag(true))]
@@ -198,10 +198,10 @@ impl Flags {
             cmd: Kind,
         }
         if let Ok(HelpVerboseOnly { help: true, verbose: 1.., cmd: subcommand }) =
-            HelpVerboseOnly::try_parse_from(it.clone())
+            HelpVerboseOnly::try_parse_from(normalize_args(args))
         {
             println!("NOTE: updating submodules before printing available paths");
-            let config = Config::parse(&[String::from("build")]);
+            let config = Config::parse(Self::parse(&[String::from("build")]));
             let build = Build::new(config);
             let paths = Builder::get_help(&build, subcommand);
             if let Some(s) = paths {
@@ -209,13 +209,23 @@ impl Flags {
             } else {
                 panic!("No paths available for subcommand `{}`", subcommand.as_str());
             }
-            crate::exit!(0);
+            true
+        } else {
+            false
         }
+    }
 
-        Flags::parse_from(it)
+    pub fn parse(args: &[String]) -> Self {
+        Flags::parse_from(normalize_args(args))
     }
 }
 
+fn normalize_args(args: &[String]) -> Vec<String> {
+    let first = String::from("x.py");
+    let it = std::iter::once(first).chain(args.iter().cloned());
+    it.collect()
+}
+
 #[derive(Debug, Clone, Default, clap::Subcommand)]
 pub enum Subcommand {
     #[command(aliases = ["b"], long_about = "\n
@@ -347,9 +357,9 @@ pub enum Subcommand {
         /// extra arguments to be passed for the test tool being used
         /// (e.g. libtest, compiletest or rustdoc)
         test_args: Vec<String>,
-        /// extra options to pass the compiler when running tests
+        /// extra options to pass the compiler when running compiletest tests
         #[arg(long, value_name = "ARGS", allow_hyphen_values(true))]
-        rustc_args: Vec<String>,
+        compiletest_rustc_args: Vec<String>,
         #[arg(long)]
         /// do not run doc tests
         no_doc: bool,
@@ -392,9 +402,6 @@ pub enum Subcommand {
         /// extra arguments to be passed for the test tool being used
         /// (e.g. libtest, compiletest or rustdoc)
         test_args: Vec<String>,
-        /// extra options to pass the compiler when running tests
-        #[arg(long, value_name = "ARGS", allow_hyphen_values(true))]
-        rustc_args: Vec<String>,
         #[arg(long)]
         /// do not run doc tests
         no_doc: bool,
@@ -499,10 +506,10 @@ impl Subcommand {
         }
     }
 
-    pub fn rustc_args(&self) -> Vec<&str> {
+    pub fn compiletest_rustc_args(&self) -> Vec<&str> {
         match *self {
-            Subcommand::Test { ref rustc_args, .. } | Subcommand::Miri { ref rustc_args, .. } => {
-                rustc_args.iter().flat_map(|s| s.split_whitespace()).collect()
+            Subcommand::Test { ref compiletest_rustc_args, .. } => {
+                compiletest_rustc_args.iter().flat_map(|s| s.split_whitespace()).collect()
             }
             _ => vec![],
         }
diff --git a/src/bootstrap/src/core/config/mod.rs b/src/bootstrap/src/core/config/mod.rs
index 23556e8bc5d..9f09dd13f29 100644
--- a/src/bootstrap/src/core/config/mod.rs
+++ b/src/bootstrap/src/core/config/mod.rs
@@ -1,6 +1,6 @@
 #[allow(clippy::module_inception)]
 mod config;
-pub(crate) mod flags;
+pub mod flags;
 #[cfg(test)]
 mod tests;
 
diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs
index bfb2c02860d..40f3e5e7222 100644
--- a/src/bootstrap/src/core/config/tests.rs
+++ b/src/bootstrap/src/core/config/tests.rs
@@ -1,22 +1,21 @@
-use super::{flags::Flags, ChangeIdWrapper, Config};
-use crate::core::build_steps::clippy::get_clippy_rules_in_order;
-use crate::core::config::Target;
-use crate::core::config::TargetSelection;
-use crate::core::config::{LldMode, TomlConfig};
+use std::env;
+use std::fs::{remove_file, File};
+use std::io::Write;
+use std::path::Path;
 
 use clap::CommandFactory;
 use serde::Deserialize;
-use std::{
-    env,
-    fs::{remove_file, File},
-    io::Write,
-    path::Path,
-};
+
+use super::flags::Flags;
+use super::{ChangeIdWrapper, Config};
+use crate::core::build_steps::clippy::get_clippy_rules_in_order;
+use crate::core::config::{LldMode, Target, TargetSelection, TomlConfig};
 
 fn parse(config: &str) -> Config {
-    Config::parse_inner(&["check".to_string(), "--config=/does/not/exist".to_string()], |&_| {
-        toml::from_str(&config).unwrap()
-    })
+    Config::parse_inner(
+        Flags::parse(&["check".to_string(), "--config=/does/not/exist".to_string()]),
+        |&_| toml::from_str(&config).unwrap(),
+    )
 }
 
 #[test]
@@ -110,7 +109,7 @@ fn clap_verify() {
 #[test]
 fn override_toml() {
     let config = Config::parse_inner(
-        &[
+        Flags::parse(&[
             "check".to_owned(),
             "--config=/does/not/exist".to_owned(),
             "--set=change-id=1".to_owned(),
@@ -123,7 +122,7 @@ fn override_toml() {
             "--set=target.x86_64-unknown-linux-gnu.rpath=false".to_owned(),
             "--set=target.aarch64-unknown-linux-gnu.sanitizers=false".to_owned(),
             "--set=target.aarch64-apple-darwin.runner=apple".to_owned(),
-        ],
+        ]),
         |&_| {
             toml::from_str(
                 r#"
@@ -203,12 +202,12 @@ runner = "x86_64-runner"
 #[should_panic]
 fn override_toml_duplicate() {
     Config::parse_inner(
-        &[
+        Flags::parse(&[
             "check".to_owned(),
             "--config=/does/not/exist".to_string(),
             "--set=change-id=1".to_owned(),
             "--set=change-id=2".to_owned(),
-        ],
+        ]),
         |&_| toml::from_str("change-id = 0").unwrap(),
     );
 }
@@ -228,7 +227,7 @@ fn profile_user_dist() {
             .and_then(|table: toml::Value| TomlConfig::deserialize(table))
             .unwrap()
     }
-    Config::parse_inner(&["check".to_owned()], get_toml);
+    Config::parse_inner(Flags::parse(&["check".to_owned()]), get_toml);
 }
 
 #[test]
@@ -303,7 +302,7 @@ fn order_of_clippy_rules() {
         "-Aclippy::foo1".to_string(),
         "-Aclippy::foo2".to_string(),
     ];
-    let config = Config::parse(&args);
+    let config = Config::parse(Flags::parse(&args));
 
     let actual = match &config.cmd {
         crate::Subcommand::Clippy { allow, deny, warn, forbid, .. } => {
diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs
index 56a8528d0a1..8131666fcb2 100644
--- a/src/bootstrap/src/core/download.rs
+++ b/src/bootstrap/src/core/download.rs
@@ -1,19 +1,16 @@
-use std::{
-    env,
-    ffi::OsString,
-    fs::{self, File},
-    io::{BufRead, BufReader, BufWriter, ErrorKind, Write},
-    path::{Path, PathBuf},
-    process::{Command, Stdio},
-    sync::OnceLock,
-};
+use std::env;
+use std::ffi::OsString;
+use std::fs::{self, File};
+use std::io::{BufRead, BufReader, BufWriter, ErrorKind, Write};
+use std::path::{Path, PathBuf};
+use std::process::{Command, Stdio};
+use std::sync::OnceLock;
 
 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::utils::helpers::{check_run, exe, hex_encode, move_file, program_out_of_date};
 use crate::{t, Config};
 
 static SHOULD_FIX_BINS_AND_DYLIBS: OnceLock<bool> = OnceLock::new();
@@ -382,7 +379,7 @@ impl Config {
         let version = &self.stage0_metadata.compiler.version;
         let host = self.build;
 
-        let bin_root = self.out.join(host.triple).join("stage0");
+        let bin_root = self.out.join(host).join("stage0");
         let clippy_stamp = bin_root.join(".clippy-stamp");
         let cargo_clippy = bin_root.join("bin").join(exe("cargo-clippy", host));
         if cargo_clippy.exists() && !program_out_of_date(&clippy_stamp, date) {
@@ -415,7 +412,7 @@ impl Config {
         let channel = format!("{version}-{date}");
 
         let host = self.build;
-        let bin_root = self.out.join(host.triple).join("rustfmt");
+        let bin_root = self.out.join(host).join("rustfmt");
         let rustfmt_path = bin_root.join("bin").join(exe("rustfmt", host));
         let rustfmt_stamp = bin_root.join(".rustfmt-stamp");
         if rustfmt_path.exists() && !program_out_of_date(&rustfmt_stamp, &channel) {
@@ -522,7 +519,7 @@ impl Config {
         extra_components: &[&str],
         download_component: fn(&Config, String, &str, &str),
     ) {
-        let host = self.build.triple;
+        let host = self.build;
         let bin_root = self.out.join(host).join(sysroot);
         let rustc_stamp = bin_root.join(".rustc-stamp");
 
@@ -595,7 +592,7 @@ impl Config {
             t!(fs::create_dir_all(&cache_dir));
         }
 
-        let bin_root = self.out.join(self.build.triple).join(destination);
+        let bin_root = self.out.join(self.build).join(destination);
         let tarball = cache_dir.join(&filename);
         let (base_url, url, should_verify) = match mode {
             DownloadSource::CI => {
diff --git a/src/bootstrap/src/core/metadata.rs b/src/bootstrap/src/core/metadata.rs
index 9b4c85e6d34..1016607fc83 100644
--- a/src/bootstrap/src/core/metadata.rs
+++ b/src/bootstrap/src/core/metadata.rs
@@ -86,6 +86,9 @@ fn workspace_members(build: &Build) -> Vec<Package> {
         packages
     };
 
-    // Collects `metadata.packages` from all workspaces.
-    collect_metadata("Cargo.toml")
+    // Collects `metadata.packages` from the root and library workspaces.
+    let mut packages = vec![];
+    packages.extend(collect_metadata("Cargo.toml"));
+    packages.extend(collect_metadata("library/Cargo.toml"));
+    packages
 }
diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs
index 8aa0c43ad6e..c42d4c56c38 100644
--- a/src/bootstrap/src/core/sanity.rs
+++ b/src/bootstrap/src/core/sanity.rs
@@ -9,19 +9,17 @@
 //! practice that's likely not true!
 
 use std::collections::HashMap;
-use std::env;
+#[cfg(not(feature = "bootstrap-self-test"))]
+use std::collections::HashSet;
 use std::ffi::{OsStr, OsString};
-use std::fs;
 use std::path::PathBuf;
+use std::{env, fs};
 
 #[cfg(not(feature = "bootstrap-self-test"))]
 use crate::builder::Builder;
+use crate::builder::Kind;
 #[cfg(not(feature = "bootstrap-self-test"))]
 use crate::core::build_steps::tool;
-#[cfg(not(feature = "bootstrap-self-test"))]
-use std::collections::HashSet;
-
-use crate::builder::Kind;
 use crate::core::config::Target;
 use crate::utils::exec::command;
 use crate::Build;
@@ -262,7 +260,9 @@ than building it.
 
             if !has_target {
                 // This might also be a custom target, so check the target file that could have been specified by the user.
-                if let Some(custom_target_path) = env::var_os("RUST_TARGET_PATH") {
+                if target.filepath().is_some_and(|p| p.exists()) {
+                    has_target = true;
+                } else if let Some(custom_target_path) = env::var_os("RUST_TARGET_PATH") {
                     let mut target_filename = OsString::from(&target_str);
                     // Target filename ends with `.json`.
                     target_filename.push(".json");
@@ -277,8 +277,12 @@ than building it.
 
             if !has_target {
                 panic!(
-                    "No such target exists in the target list,
-                specify a correct location of the JSON specification file for custom targets!"
+                    "No such target exists in the target list,\n\
+                     make sure to correctly specify the location \
+                     of the JSON specification file \
+                     for custom targets!\n\
+                     Use BOOTSTRAP_SKIP_TARGET_SANITY=1 to \
+                     bypass this check."
                 );
             }
         }
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 1bcae250c3f..bfd0e42acfd 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -18,17 +18,15 @@
 
 use std::cell::{Cell, RefCell};
 use std::collections::{HashMap, HashSet};
-use std::env;
 use std::fmt::Display;
 use std::fs::{self, File};
-use std::io;
 use std::path::{Path, PathBuf};
 use std::process::Command;
-use std::str;
 use std::sync::OnceLock;
 use std::time::SystemTime;
+use std::{env, io, str};
 
-use build_helper::ci::{gha, CiEnv};
+use build_helper::ci::gha;
 use build_helper::exit;
 use sha2::digest::Digest;
 use termcolor::{ColorChoice, StandardStream, WriteColor};
@@ -37,9 +35,7 @@ use utils::helpers::hex_encode;
 
 use crate::core::builder;
 use crate::core::builder::{Builder, Kind};
-use crate::core::config::{flags, LldMode};
-use crate::core::config::{DryRun, Target};
-use crate::core::config::{LlvmLibunwind, TargetSelection};
+use crate::core::config::{flags, DryRun, LldMode, LlvmLibunwind, Target, TargetSelection};
 use crate::utils::exec::{command, BehaviorOnFailure, BootstrapCommand, CommandOutput, OutputMode};
 use crate::utils::helpers::{self, dir_is_empty, exe, libdir, mtime, output, symlink_dir};
 
@@ -47,8 +43,9 @@ mod core;
 mod utils;
 
 pub use core::builder::PathSet;
-pub use core::config::flags::Subcommand;
+pub use core::config::flags::{Flags, Subcommand};
 pub use core::config::Config;
+
 pub use utils::change_tracker::{
     find_recent_config_change_ids, human_readable_changes, CONFIG_CHANGE_HISTORY,
 };
@@ -171,7 +168,6 @@ pub struct Build {
     crates: HashMap<String, Crate>,
     crate_paths: HashMap<PathBuf, String>,
     is_sudo: bool,
-    ci_env: CiEnv,
     delayed_failures: RefCell<Vec<String>>,
     prerelease_version: Cell<Option<u32>>,
 
@@ -403,7 +399,6 @@ impl Build {
             crates: HashMap::new(),
             crate_paths: HashMap::new(),
             is_sudo,
-            ci_env: CiEnv::current(),
             delayed_failures: RefCell::new(Vec::new()),
             prerelease_version: Cell::new(None),
 
@@ -441,7 +436,13 @@ impl Build {
             // Cargo.toml files.
             let rust_submodules = ["library/backtrace", "library/stdarch"];
             for s in rust_submodules {
-                build.update_submodule(Path::new(s));
+                build.require_submodule(
+                    s,
+                    Some(
+                        "The submodule is required for the standard library \
+                         and the main Cargo workspace.",
+                    ),
+                );
             }
             // Now, update all existing submodules.
             build.update_existing_submodules();
@@ -451,7 +452,7 @@ impl Build {
         }
 
         // Make a symbolic link so we can use a consistent directory in the documentation.
-        let build_triple = build.out.join(build.build.triple);
+        let build_triple = build.out.join(build.build);
         t!(fs::create_dir_all(&build_triple));
         let host = build.out.join("host");
         if host.is_symlink() {
@@ -470,12 +471,17 @@ impl Build {
         build
     }
 
-    // modified from `check_submodule` and `update_submodule` in bootstrap.py
     /// Given a path to the directory of a submodule, update it.
     ///
     /// `relative_path` should be relative to the root of the git repository, not an absolute path.
-    pub(crate) fn update_submodule(&self, relative_path: &Path) {
-        if !self.config.submodules(self.rust_info()) {
+    ///
+    /// This *does not* update the submodule if `config.toml` explicitly says
+    /// not to, or if we're not in a git repository (like a plain source
+    /// tarball). Typically [`Build::require_submodule`] should be
+    /// used instead to provide a nice error to the user if the submodule is
+    /// missing.
+    fn update_submodule(&self, relative_path: &str) {
+        if !self.config.submodules() {
             return;
         }
 
@@ -522,7 +528,7 @@ impl Build {
             return;
         }
 
-        println!("Updating submodule {}", relative_path.display());
+        println!("Updating submodule {relative_path}");
         helpers::git(Some(&self.src))
             .run_always()
             .args(["submodule", "-q", "sync"])
@@ -576,11 +582,53 @@ impl Build {
         }
     }
 
+    /// Updates a submodule, and exits with a failure if submodule management
+    /// is disabled and the submodule does not exist.
+    ///
+    /// The given submodule name should be its path relative to the root of
+    /// the main repository.
+    ///
+    /// The given `err_hint` will be shown to the user if the submodule is not
+    /// checked out and submodule management is disabled.
+    pub fn require_submodule(&self, submodule: &str, err_hint: Option<&str>) {
+        // When testing bootstrap itself, it is much faster to ignore
+        // submodules. Almost all Steps work fine without their submodules.
+        if cfg!(test) && !self.config.submodules() {
+            return;
+        }
+        self.update_submodule(submodule);
+        let absolute_path = self.config.src.join(submodule);
+        if dir_is_empty(&absolute_path) {
+            let maybe_enable = if !self.config.submodules()
+                && self.config.rust_info.is_managed_git_subrepository()
+            {
+                "\nConsider setting `build.submodules = true` or manually initializing the submodules."
+            } else {
+                ""
+            };
+            let err_hint = err_hint.map_or_else(String::new, |e| format!("\n{e}"));
+            eprintln!(
+                "submodule {submodule} does not appear to be checked out, \
+                 but it is required for this step{maybe_enable}{err_hint}"
+            );
+            exit!(1);
+        }
+    }
+
+    /// Updates all submodules, and exits with an error if submodule
+    /// management is disabled and the submodule does not exist.
+    pub fn require_and_update_all_submodules(&self) {
+        for submodule in build_helper::util::parse_gitmodules(&self.src) {
+            self.require_submodule(submodule, None);
+        }
+    }
+
     /// If any submodule has been initialized already, sync it unconditionally.
     /// This avoids contributors checking in a submodule change by accident.
-    pub fn update_existing_submodules(&self) {
-        // Avoid running git when there isn't a git checkout.
-        if !self.config.submodules(self.rust_info()) {
+    fn update_existing_submodules(&self) {
+        // Avoid running git when there isn't a git checkout, or the user has
+        // explicitly disabled submodules in `config.toml`.
+        if !self.config.submodules() {
             return;
         }
         let output = helpers::git(Some(&self.src))
@@ -592,22 +640,23 @@ impl Build {
         for line in output.lines() {
             // Look for `submodule.$name.path = $path`
             // Sample output: `submodule.src/rust-installer.path src/tools/rust-installer`
-            let submodule = Path::new(line.split_once(' ').unwrap().1);
+            let submodule = line.split_once(' ').unwrap().1;
+            let path = Path::new(submodule);
             // Don't update the submodule unless it's already been cloned.
-            if GitInfo::new(false, submodule).is_managed_git_subrepository() {
+            if GitInfo::new(false, path).is_managed_git_subrepository() {
                 self.update_submodule(submodule);
             }
         }
     }
 
     /// Updates the given submodule only if it's initialized already; nothing happens otherwise.
-    pub fn update_existing_submodule(&self, submodule: &Path) {
+    pub fn update_existing_submodule(&self, submodule: &str) {
         // Avoid running git when there isn't a git checkout.
-        if !self.config.submodules(self.rust_info()) {
+        if !self.config.submodules() {
             return;
         }
 
-        if GitInfo::new(false, submodule).is_managed_git_subrepository() {
+        if GitInfo::new(false, Path::new(submodule)).is_managed_git_subrepository() {
             self.update_submodule(submodule);
         }
     }
@@ -758,10 +807,7 @@ impl Build {
     }
 
     fn tools_dir(&self, compiler: Compiler) -> PathBuf {
-        let out = self
-            .out
-            .join(&*compiler.host.triple)
-            .join(format!("stage{}-tools-bin", compiler.stage));
+        let out = self.out.join(compiler.host).join(format!("stage{}-tools-bin", compiler.stage));
         t!(fs::create_dir_all(&out));
         out
     }
@@ -778,14 +824,14 @@ impl Build {
             Mode::ToolBootstrap => "-bootstrap-tools",
             Mode::ToolStd | Mode::ToolRustc => "-tools",
         };
-        self.out.join(&*compiler.host.triple).join(format!("stage{}{}", compiler.stage, suffix))
+        self.out.join(compiler.host).join(format!("stage{}{}", compiler.stage, suffix))
     }
 
     /// Returns the root output directory for all Cargo output in a given stage,
     /// running a particular compiler, whether or not we're building the
     /// standard library, and targeting the specified architecture.
     fn cargo_out(&self, compiler: Compiler, mode: Mode, target: TargetSelection) -> PathBuf {
-        self.stage_out(compiler, mode).join(&*target.triple).join(self.cargo_dir())
+        self.stage_out(compiler, mode).join(target).join(self.cargo_dir())
     }
 
     /// Root output directory of LLVM for `target`
@@ -796,36 +842,36 @@ impl Build {
         if self.config.llvm_from_ci && self.config.build == target {
             self.config.ci_llvm_root()
         } else {
-            self.out.join(&*target.triple).join("llvm")
+            self.out.join(target).join("llvm")
         }
     }
 
     fn lld_out(&self, target: TargetSelection) -> PathBuf {
-        self.out.join(&*target.triple).join("lld")
+        self.out.join(target).join("lld")
     }
 
     /// Output directory for all documentation for a target
     fn doc_out(&self, target: TargetSelection) -> PathBuf {
-        self.out.join(&*target.triple).join("doc")
+        self.out.join(target).join("doc")
     }
 
     /// Output directory for all JSON-formatted documentation for a target
     fn json_doc_out(&self, target: TargetSelection) -> PathBuf {
-        self.out.join(&*target.triple).join("json-doc")
+        self.out.join(target).join("json-doc")
     }
 
     fn test_out(&self, target: TargetSelection) -> PathBuf {
-        self.out.join(&*target.triple).join("test")
+        self.out.join(target).join("test")
     }
 
     /// Output directory for all documentation for a target
     fn compiler_doc_out(&self, target: TargetSelection) -> PathBuf {
-        self.out.join(&*target.triple).join("compiler-doc")
+        self.out.join(target).join("compiler-doc")
     }
 
     /// Output directory for some generated md crate documentation for a target (temporary)
     fn md_doc_out(&self, target: TargetSelection) -> PathBuf {
-        self.out.join(&*target.triple).join("md-doc")
+        self.out.join(target).join("md-doc")
     }
 
     /// Returns `true` if this is an external version of LLVM not managed by bootstrap.
@@ -905,7 +951,7 @@ impl Build {
 
     /// Directory for libraries built from C/C++ code and shared between stages.
     fn native_dir(&self, target: TargetSelection) -> PathBuf {
-        self.out.join(&*target.triple).join("native")
+        self.out.join(target).join("native")
     }
 
     /// Root output directory for rust_test_helpers library compiled for
@@ -937,7 +983,8 @@ impl Build {
     }
 
     /// Execute a command and return its output.
-    /// This method should be used for all command executions in bootstrap.
+    /// Note: Ideally, you should use one of the BootstrapCommand::run* functions to
+    /// execute commands. They internally call this method.
     #[track_caller]
     fn run(
         &self,
@@ -1008,20 +1055,28 @@ Executed at: {executed_at}"#,
                 CommandOutput::did_not_start(stdout, stderr)
             }
         };
+
+        let fail = |message: &str| {
+            if self.is_verbose() {
+                println!("{message}");
+            } else {
+                println!("Command has failed. Rerun with -v to see more details.");
+            }
+            exit!(1);
+        };
+
         if !output.is_success() {
             match command.failure_behavior {
                 BehaviorOnFailure::DelayFail => {
                     if self.fail_fast {
-                        println!("{message}");
-                        exit!(1);
+                        fail(&message);
                     }
 
                     let mut failures = self.delayed_failures.borrow_mut();
                     failures.push(message);
                 }
                 BehaviorOnFailure::Exit => {
-                    println!("{message}");
-                    exit!(1);
+                    fail(&message);
                 }
                 BehaviorOnFailure::Ignore => {
                     // If failures are allowed, either the error has been printed already
diff --git a/src/bootstrap/src/utils/cache.rs b/src/bootstrap/src/utils/cache.rs
index d60b54dc703..3f78b04d44a 100644
--- a/src/bootstrap/src/utils/cache.rs
+++ b/src/bootstrap/src/utils/cache.rs
@@ -3,13 +3,12 @@ use std::borrow::Borrow;
 use std::cell::RefCell;
 use std::cmp::Ordering;
 use std::collections::HashMap;
-use std::fmt;
 use std::hash::{Hash, Hasher};
 use std::marker::PhantomData;
-use std::mem;
 use std::ops::Deref;
 use std::path::PathBuf;
 use std::sync::{LazyLock, Mutex};
+use std::{fmt, mem};
 
 use crate::core::builder::Step;
 
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index b8f70fdf6a8..c629f04c00e 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -220,4 +220,14 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Warning,
         summary: "For tarball sources, default value for `rust.channel` will be taken from `src/ci/channel` file.",
     },
+    ChangeInfo {
+        change_id: 125642,
+        severity: ChangeSeverity::Info,
+        summary: "New option `llvm.libzstd` to control whether llvm is built with zstd support.",
+    },
+    ChangeInfo {
+        change_id: 128841,
+        severity: ChangeSeverity::Warning,
+        summary: "./x test --rustc-args was renamed to --compiletest-rustc-args as it only applies there. ./x miri --rustc-args was also removed.",
+    },
 ];
diff --git a/src/bootstrap/src/utils/channel.rs b/src/bootstrap/src/utils/channel.rs
index f8bcb584991..3ae512ef7f1 100644
--- a/src/bootstrap/src/utils/channel.rs
+++ b/src/bootstrap/src/utils/channel.rs
@@ -8,11 +8,10 @@
 use std::fs;
 use std::path::Path;
 
+use super::helpers;
 use crate::utils::helpers::{output, t};
 use crate::Build;
 
-use super::helpers;
-
 #[derive(Clone, Default)]
 pub enum GitInfo {
     /// This is not a git repository.
diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs
index 627ea050043..9f0d0b7e969 100644
--- a/src/bootstrap/src/utils/exec.rs
+++ b/src/bootstrap/src/utils/exec.rs
@@ -1,11 +1,13 @@
-use crate::Build;
-use build_helper::ci::CiEnv;
-use build_helper::drop_bomb::DropBomb;
 use std::ffi::OsStr;
 use std::fmt::{Debug, Formatter};
 use std::path::Path;
 use std::process::{Command, CommandArgs, CommandEnvs, ExitStatus, Output, Stdio};
 
+use build_helper::ci::CiEnv;
+use build_helper::drop_bomb::DropBomb;
+
+use crate::Build;
+
 /// What should be done when the command fails.
 #[derive(Debug, Copy, Clone)]
 pub enum BehaviorOnFailure {
@@ -173,8 +175,8 @@ impl BootstrapCommand {
     }
 
     /// If in a CI environment, forces the command to run with colors.
-    pub fn force_coloring_in_ci(&mut self, ci_env: CiEnv) {
-        if ci_env != CiEnv::None {
+    pub fn force_coloring_in_ci(&mut self) {
+        if CiEnv::is_ci() {
             // Due to use of stamp/docker, the output stream of bootstrap is not
             // a TTY in CI, so coloring is by-default turned off.
             // The explicit `TERM=xterm` environment is needed for
diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs
index 51c14ff6282..65e75f114bb 100644
--- a/src/bootstrap/src/utils/helpers.rs
+++ b/src/bootstrap/src/utils/helpers.rs
@@ -3,23 +3,20 @@
 //! Simple things like testing the various filesystem operations here and there,
 //! not a lot of interesting happenings here unfortunately.
 
-use build_helper::git::{get_git_merge_base, output_result, GitConfig};
-use build_helper::util::fail;
-use std::env;
 use std::ffi::OsStr;
-use std::fs;
-use std::io;
 use std::path::{Path, PathBuf};
 use std::process::{Command, Stdio};
-use std::str;
 use std::sync::OnceLock;
 use std::time::{Instant, SystemTime, UNIX_EPOCH};
+use std::{env, fs, io, str};
+
+use build_helper::git::{get_git_merge_base, output_result, GitConfig};
+use build_helper::util::fail;
 
 use crate::core::builder::Builder;
 use crate::core::config::{Config, TargetSelection};
-use crate::LldMode;
-
 pub use crate::utils::shared_helpers::{dylib_path, dylib_path_var};
+use crate::LldMode;
 
 #[cfg(test)]
 mod tests;
@@ -48,9 +45,10 @@ macro_rules! t {
         }
     };
 }
-use crate::utils::exec::{command, BootstrapCommand};
 pub use t;
 
+use crate::utils::exec::{command, BootstrapCommand};
+
 pub fn exe(name: &str, target: TargetSelection) -> String {
     crate::utils::shared_helpers::exe(name, &target.triple)
 }
@@ -538,8 +536,7 @@ pub fn get_closest_merge_base_commit(
 
     let merge_base = get_git_merge_base(config, source_dir).unwrap_or_else(|_| "HEAD".into());
 
-    git.arg(Path::new("rev-list"));
-    git.args([&format!("--author={author}"), "-n1", "--first-parent", &merge_base]);
+    git.args(["rev-list", &format!("--author={author}"), "-n1", "--first-parent", &merge_base]);
 
     if !target_paths.is_empty() {
         git.arg("--").args(target_paths);
diff --git a/src/bootstrap/src/utils/helpers/tests.rs b/src/bootstrap/src/utils/helpers/tests.rs
index 2ab3952ae5a..103c4d26a18 100644
--- a/src/bootstrap/src/utils/helpers/tests.rs
+++ b/src/bootstrap/src/utils/helpers/tests.rs
@@ -1,14 +1,11 @@
-use crate::{
-    utils::helpers::{
-        check_cfg_arg, extract_beta_rev, hex_encode, make, program_out_of_date, symlink_dir,
-    },
-    Config,
-};
-use std::{
-    fs::{self, remove_file, File},
-    io::Write,
-    path::PathBuf,
+use std::fs::{self, remove_file, File};
+use std::io::Write;
+use std::path::PathBuf;
+
+use crate::utils::helpers::{
+    check_cfg_arg, extract_beta_rev, hex_encode, make, program_out_of_date, symlink_dir,
 };
+use crate::{Config, Flags};
 
 #[test]
 fn test_make() {
@@ -61,7 +58,8 @@ fn test_check_cfg_arg() {
 
 #[test]
 fn test_program_out_of_date() {
-    let config = Config::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()]);
+    let config =
+        Config::parse(Flags::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()]));
     let tempfile = config.tempdir().join(".tmp-stamp-file");
     File::create(&tempfile).unwrap().write_all(b"dummy value").unwrap();
     assert!(tempfile.exists());
@@ -76,7 +74,8 @@ fn test_program_out_of_date() {
 
 #[test]
 fn test_symlink_dir() {
-    let config = Config::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()]);
+    let config =
+        Config::parse(Flags::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()]));
     let tempdir = config.tempdir().join(".tmp-dir");
     let link_path = config.tempdir().join(".tmp-link");
 
diff --git a/src/bootstrap/src/utils/job.rs b/src/bootstrap/src/utils/job.rs
index d7d20e57bd1..4012f5167ff 100644
--- a/src/bootstrap/src/utils/job.rs
+++ b/src/bootstrap/src/utils/job.rs
@@ -40,28 +40,25 @@ pub unsafe fn setup(build: &mut crate::Build) {
 /// Note that this is a Windows specific module as none of this logic is required on Unix.
 #[cfg(windows)]
 mod for_windows {
-    use crate::Build;
-    use std::env;
     use std::ffi::c_void;
-    use std::io;
-    use std::mem;
+    use std::{env, io, mem};
 
-    use windows::{
-        core::PCWSTR,
-        Win32::Foundation::{CloseHandle, DuplicateHandle, DUPLICATE_SAME_ACCESS, HANDLE},
-        Win32::System::Diagnostics::Debug::{
-            SetErrorMode, SEM_NOGPFAULTERRORBOX, THREAD_ERROR_MODE,
-        },
-        Win32::System::JobObjects::{
-            AssignProcessToJobObject, CreateJobObjectW, JobObjectExtendedLimitInformation,
-            SetInformationJobObject, JOBOBJECT_EXTENDED_LIMIT_INFORMATION,
-            JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, JOB_OBJECT_LIMIT_PRIORITY_CLASS,
-        },
-        Win32::System::Threading::{
-            GetCurrentProcess, OpenProcess, BELOW_NORMAL_PRIORITY_CLASS, PROCESS_DUP_HANDLE,
-        },
+    use windows::core::PCWSTR;
+    use windows::Win32::Foundation::{CloseHandle, DuplicateHandle, DUPLICATE_SAME_ACCESS, HANDLE};
+    use windows::Win32::System::Diagnostics::Debug::{
+        SetErrorMode, SEM_NOGPFAULTERRORBOX, THREAD_ERROR_MODE,
+    };
+    use windows::Win32::System::JobObjects::{
+        AssignProcessToJobObject, CreateJobObjectW, JobObjectExtendedLimitInformation,
+        SetInformationJobObject, JOBOBJECT_EXTENDED_LIMIT_INFORMATION,
+        JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, JOB_OBJECT_LIMIT_PRIORITY_CLASS,
+    };
+    use windows::Win32::System::Threading::{
+        GetCurrentProcess, OpenProcess, BELOW_NORMAL_PRIORITY_CLASS, PROCESS_DUP_HANDLE,
     };
 
+    use crate::Build;
+
     pub unsafe fn setup(build: &mut Build) {
         // Enable the Windows Error Reporting dialog which msys disables,
         // so we can JIT debug rustc
diff --git a/src/bootstrap/src/utils/metrics.rs b/src/bootstrap/src/utils/metrics.rs
index 697dd2f3505..e9acb93363e 100644
--- a/src/bootstrap/src/utils/metrics.rs
+++ b/src/bootstrap/src/utils/metrics.rs
@@ -4,18 +4,20 @@
 //! As this module requires additional dependencies not present during local builds, it's cfg'd
 //! away whenever the `build.metrics` config option is not set to `true`.
 
-use crate::core::builder::{Builder, Step};
-use crate::utils::helpers::t;
-use crate::Build;
-use build_helper::metrics::{
-    JsonInvocation, JsonInvocationSystemStats, JsonNode, JsonRoot, JsonStepSystemStats, Test,
-    TestOutcome, TestSuite, TestSuiteMetadata,
-};
 use std::cell::RefCell;
 use std::fs::File;
 use std::io::BufWriter;
 use std::time::{Duration, Instant, SystemTime};
-use sysinfo::System;
+
+use build_helper::metrics::{
+    JsonInvocation, JsonInvocationSystemStats, JsonNode, JsonRoot, JsonStepSystemStats, Test,
+    TestOutcome, TestSuite, TestSuiteMetadata,
+};
+use sysinfo::{CpuRefreshKind, RefreshKind, System};
+
+use crate::core::builder::{Builder, Step};
+use crate::utils::helpers::t;
+use crate::Build;
 
 // Update this number whenever a breaking change is made to the build metrics.
 //
@@ -53,7 +55,9 @@ impl BuildMetrics {
             finished_steps: Vec::new(),
             running_steps: Vec::new(),
 
-            system_info: System::new(),
+            system_info: System::new_with_specifics(
+                RefreshKind::new().with_cpu(CpuRefreshKind::everything()),
+            ),
             timer_start: None,
             invocation_timer_start: Instant::now(),
             invocation_start: SystemTime::now(),
@@ -75,7 +79,7 @@ impl BuildMetrics {
             self.collect_stats(&mut *state);
         }
 
-        state.system_info.refresh_cpu();
+        state.system_info.refresh_cpu_usage();
         state.timer_start = Some(Instant::now());
 
         state.running_steps.push(StepMetrics {
@@ -108,7 +112,7 @@ impl BuildMetrics {
             state.running_steps.last_mut().unwrap().children.push(step);
 
             // Start collecting again for the parent step.
-            state.system_info.refresh_cpu();
+            state.system_info.refresh_cpu_usage();
             state.timer_start = Some(Instant::now());
         }
     }
@@ -146,7 +150,7 @@ impl BuildMetrics {
         let elapsed = state.timer_start.unwrap().elapsed();
         step.duration_excluding_children_sec += elapsed;
 
-        state.system_info.refresh_cpu();
+        state.system_info.refresh_cpu_usage();
         let cpu = state.system_info.cpus().iter().map(|p| p.cpu_usage()).sum::<f32>();
         step.cpu_usage_time_sec += cpu as f64 / 100.0 * elapsed.as_secs_f64();
     }
@@ -157,8 +161,9 @@ impl BuildMetrics {
 
         let dest = build.out.join("metrics.json");
 
-        let mut system = System::new();
-        system.refresh_cpu();
+        let mut system =
+            System::new_with_specifics(RefreshKind::new().with_cpu(CpuRefreshKind::everything()));
+        system.refresh_cpu_usage();
         system.refresh_memory();
 
         let system_stats = JsonInvocationSystemStats {
diff --git a/src/bootstrap/src/utils/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs
index a3d0d36e754..b8aebc28549 100644
--- a/src/bootstrap/src/utils/render_tests.rs
+++ b/src/bootstrap/src/utils/render_tests.rs
@@ -6,13 +6,15 @@
 //! and rustc) libtest doesn't include the rendered human-readable output as a JSON field. We had
 //! 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, Stdio};
 use std::time::Duration;
+
 use termcolor::{Color, ColorSpec, WriteColor};
 
+use crate::core::builder::Builder;
+use crate::utils::exec::BootstrapCommand;
+
 const TERSE_TESTS_PER_LINE: usize = 88;
 
 pub(crate) fn add_flags_and_try_run_tests(
diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs
index cef67ae4c37..3f7f6214cf6 100644
--- a/src/bootstrap/src/utils/tarball.rs
+++ b/src/bootstrap/src/utils/tarball.rs
@@ -7,8 +7,8 @@
 
 use std::path::{Path, PathBuf};
 
-use crate::core::builder::Builder;
-use crate::core::{build_steps::dist::distdir, builder::Kind};
+use crate::core::build_steps::dist::distdir;
+use crate::core::builder::{Builder, Kind};
 use crate::utils::exec::BootstrapCommand;
 use crate::utils::helpers::{move_file, t};
 use crate::utils::{channel, helpers};
@@ -317,6 +317,12 @@ impl<'a> Tarball<'a> {
             channel::write_commit_hash_file(&self.overlay_dir, &info.sha);
             channel::write_commit_info_file(&self.overlay_dir, info);
         }
+
+        // Add config file if present.
+        if let Some(config) = &self.builder.config.config {
+            self.add_renamed_file(config, &self.overlay_dir, "builder-config");
+        }
+
         for file in self.overlay.legal_and_readme() {
             self.builder.install(&self.builder.src.join(file), &self.overlay_dir, 0o644);
         }
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 2621e9a6031..1b98d541693 100644
--- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
@@ -24,7 +24,8 @@ RUN apt-get update && apt-get build-dep -y clang llvm && apt-get install -y --no
   # Needed for apt-key to work:
   dirmngr \
   gpg-agent \
-  g++-9-arm-linux-gnueabi
+  g++-9-arm-linux-gnueabi \
+  g++-11-riscv64-linux-gnu
 
 RUN apt-key adv --batch --yes --keyserver keyserver.ubuntu.com --recv-keys 74DA7924C5513486
 RUN add-apt-repository -y 'deb https://apt.dilos.org/dilos dilos2 main'
@@ -73,6 +74,10 @@ RUN env \
     CC=arm-linux-gnueabi-gcc-9 CFLAGS="-march=armv7-a" \
     CXX=arm-linux-gnueabi-g++-9 CXXFLAGS="-march=armv7-a" \
     bash musl.sh armv7 && \
+    env \
+    CC=riscv64-linux-gnu-gcc-11 \
+    CXX=riscv64-linux-gnu-g++-11 \
+    bash musl.sh riscv64gc && \
     rm -rf /build/*
 
 WORKDIR /tmp
@@ -125,6 +130,7 @@ ENV TARGETS=$TARGETS,x86_64-unknown-none
 ENV TARGETS=$TARGETS,aarch64-unknown-uefi
 ENV TARGETS=$TARGETS,i686-unknown-uefi
 ENV TARGETS=$TARGETS,x86_64-unknown-uefi
+ENV TARGETS=$TARGETS,riscv64gc-unknown-linux-musl
 
 # As per https://bugs.launchpad.net/ubuntu/+source/gcc-defaults/+bug/1300211
 # we need asm in the search path for gcc-9 (for gnux32) but not in the search path of the
@@ -132,7 +138,11 @@ ENV TARGETS=$TARGETS,x86_64-unknown-uefi
 # Luckily one of the folders is /usr/local/include so symlink /usr/include/x86_64-linux-gnu/asm there
 RUN ln -s /usr/include/x86_64-linux-gnu/asm /usr/local/include/asm
 
+# musl-gcc can't find libgcc_s.so.1 since it doesn't use the standard search paths.
+RUN ln -s /usr/riscv64-linux-gnu/lib/libgcc_s.so.1 /usr/lib/gcc-cross/riscv64-linux-gnu/11/
+
 ENV RUST_CONFIGURE_ARGS --enable-extended --enable-lld --enable-llvm-bitcode-linker --disable-docs \
-  --musl-root-armv7=/musl-armv7
+  --musl-root-armv7=/musl-armv7 \
+  --musl-root-riscv64gc=/musl-riscv64gc
 
 ENV SCRIPT python3 ../x.py dist --host='' --target $TARGETS
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
index 4aa1a3ccc2a..61e9694f1e2 100644
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
@@ -62,6 +62,10 @@ COPY host-x86_64/dist-x86_64-linux/build-clang.sh /tmp/
 RUN ./build-clang.sh
 ENV CC=clang CXX=clang++
 
+# rustc's LLVM needs zstd.
+COPY scripts/zstd.sh /tmp/
+RUN ./zstd.sh
+
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
@@ -79,6 +83,7 @@ ENV RUST_CONFIGURE_ARGS \
       --set target.x86_64-unknown-linux-gnu.ranlib=/rustroot/bin/llvm-ranlib \
       --set llvm.thin-lto=true \
       --set llvm.ninja=false \
+      --set llvm.libzstd=true \
       --set rust.jemalloc \
       --set rust.use-lld=true \
       --set rust.lto=thin \
diff --git a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/src/main.rs b/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/src/main.rs
index 2ec554c140b..d75ee147799 100644
--- a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/src/main.rs
+++ b/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/src/main.rs
@@ -5,6 +5,7 @@
 #![no_std]
 
 use core::{panic, ptr};
+
 use r_efi::efi::{Char16, Handle, Status, SystemTable, RESET_SHUTDOWN};
 
 #[panic_handler]
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile
index 9025e9bb0a3..19683317126 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile
@@ -17,6 +17,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   pkg-config \
   xz-utils \
   mingw-w64 \
+  zlib1g-dev \
+  libzstd-dev \
   && rm -rf /var/lib/apt/lists/*
 
 COPY scripts/sccache.sh /scripts/
diff --git a/src/ci/docker/scripts/fuchsia-test-runner.py b/src/ci/docker/scripts/fuchsia-test-runner.py
index 00269e68422..a5458b8645d 100755
--- a/src/ci/docker/scripts/fuchsia-test-runner.py
+++ b/src/ci/docker/scripts/fuchsia-test-runner.py
@@ -571,6 +571,19 @@ class TestEnvironment:
         )
 
         # Start repository server
+        # Note that we must first enable the repository server daemon.
+        check_call_with_logging(
+            [
+                ffx_path,
+                "config",
+                "set",
+                "repository.server.enabled",
+                "true",
+            ],
+            env=ffx_env,
+            stdout_handler=self.subprocess_logger.debug,
+            stderr_handler=self.subprocess_logger.debug,
+        )
         check_call_with_logging(
             [
                 ffx_path,
diff --git a/src/ci/docker/scripts/rfl-build.sh b/src/ci/docker/scripts/rfl-build.sh
index da7b029ca73..d690aac27fa 100755
--- a/src/ci/docker/scripts/rfl-build.sh
+++ b/src/ci/docker/scripts/rfl-build.sh
@@ -2,7 +2,7 @@
 
 set -euo pipefail
 
-LINUX_VERSION=c13320499ba0efd93174ef6462ae8a7a2933f6e7
+LINUX_VERSION=v6.11-rc1
 
 # Build rustc, rustdoc and cargo
 ../x.py build --stage 1 library rustdoc
@@ -65,4 +65,8 @@ make -C linux LLVM=1 -j$(($(nproc) + 1)) \
 make -C linux LLVM=1 -j$(($(nproc) + 1)) \
     samples/rust/rust_minimal.o \
     samples/rust/rust_print.o \
-    drivers/net/phy/ax88796b_rust.o
+    drivers/net/phy/ax88796b_rust.o \
+    rust/doctests_kernel_generated.o
+
+make -C linux LLVM=1 -j$(($(nproc) + 1)) \
+    rustdoc
diff --git a/src/ci/docker/scripts/x86_64-gnu-llvm.sh b/src/ci/docker/scripts/x86_64-gnu-llvm.sh
index b3921f11421..98290f5a72c 100755
--- a/src/ci/docker/scripts/x86_64-gnu-llvm.sh
+++ b/src/ci/docker/scripts/x86_64-gnu-llvm.sh
@@ -18,9 +18,9 @@ if [[ -z "${PR_CI_JOB}" ]]; then
     # compiler, and is sensitive to the addition of new flags.
     ../x.py --stage 1 test tests/ui-fulldeps
 
-    # The tests are run a second time with the size optimizations enabled.
-    ../x.py --stage 1 test library/std library/alloc library/core \
-        --rustc-args "--cfg feature=\"optimize_for_size\""
+    # Rebuild the stdlib with the size optimizations enabled and run tests again.
+    RUSTFLAGS_NOT_BOOTSTRAP="--cfg feature=\"optimize_for_size\"" ../x.py --stage 1 test \
+        library/std library/alloc library/core
 fi
 
 # NOTE: intentionally uses all of `x.py`, `x`, and `x.ps1` to make sure they all work on Linux.
diff --git a/src/ci/docker/scripts/zstd.sh b/src/ci/docker/scripts/zstd.sh
new file mode 100755
index 00000000000..a3d37ccc311
--- /dev/null
+++ b/src/ci/docker/scripts/zstd.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+set -ex
+
+hide_output() {
+  set +x
+  on_err="
+echo ERROR: An error was encountered with the build.
+cat /tmp/zstd_build.log
+exit 1
+"
+  trap "$on_err" ERR
+  bash -c "while true; do sleep 30; echo \$(date) - building ...; done" &
+  PING_LOOP_PID=$!
+  "$@" &> /tmp/zstd_build.log
+  trap - ERR
+  kill $PING_LOOP_PID
+  rm /tmp/zstd_build.log
+  set -x
+}
+
+ZSTD=1.5.6
+curl -L https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz | tar xzf -
+
+cd zstd-$ZSTD
+CFLAGS=-fPIC hide_output make -j$(nproc) VERBOSE=1
+hide_output make install
+
+cd ..
+rm -rf zstd-$ZSTD
diff --git a/src/doc/reference b/src/doc/reference
-Subproject e2f0bdc4031866734661dcdb548184bde1450ba
+Subproject 2e191814f163ee1e77e2d6094eee4dd78a289c5
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index 292b6032f84..467fd6f43e4 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -65,6 +65,8 @@
     - [riscv32im-risc0-zkvm-elf](platform-support/riscv32im-risc0-zkvm-elf.md)
     - [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md)
     - [riscv32*-unknown-none-elf](platform-support/riscv32-unknown-none-elf.md)
+    - [riscv64gc-unknown-linux-gnu](platform-support/riscv64gc-unknown-linux-gnu.md)
+    - [riscv64gc-unknown-linux-musl](platform-support/riscv64gc-unknown-linux-musl.md)
     - [sparc-unknown-none-elf](./platform-support/sparc-unknown-none-elf.md)
     - [*-pc-windows-gnullvm](platform-support/pc-windows-gnullvm.md)
     - [\*-nto-qnx-\*](platform-support/nto-qnx.md)
@@ -74,6 +76,7 @@
     - [*-unknown-openbsd](platform-support/openbsd.md)
     - [*-unknown-redox](platform-support/redox.md)
     - [\*-unknown-uefi](platform-support/unknown-uefi.md)
+    - [\*-wrs-vxworks](platform-support/vxworks.md)
     - [wasm32-wasip1](platform-support/wasm32-wasip1.md)
     - [wasm32-wasip1-threads](platform-support/wasm32-wasip1-threads.md)
     - [wasm32-wasip2](platform-support/wasm32-wasip2.md)
diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md
index 72ab8ab5ce9..fa23e3e414d 100644
--- a/src/doc/rustc/src/command-line-arguments.md
+++ b/src/doc/rustc/src/command-line-arguments.md
@@ -96,9 +96,7 @@ This modifier translates to `--whole-archive` for `ld`-like linkers,
 to `/WHOLEARCHIVE` for `link.exe`, and to `-force_load` for `ld64`.
 The modifier does nothing for linkers that don't support it.
 
-The default for this modifier is `-whole-archive`. \
-NOTE: The default may currently be different in some cases for backward compatibility,
-but it is not guaranteed. If you need whole archive semantics use `+whole-archive` explicitly.
+The default for this modifier is `-whole-archive`.
 
 ### Linking modifiers: `bundle`
 
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 0c7f4e7bf1b..bd12172ecbb 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -33,6 +33,7 @@ All tier 1 targets with host tools support the full standard library.
 target | notes
 -------|-------
 `aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.1, glibc 2.17+)
+[`aarch64-apple-darwin`](platform-support/apple-darwin.md) | ARM64 macOS (11.0+, Big Sur+)
 `i686-pc-windows-gnu` | 32-bit MinGW (Windows 10+, Windows Server 2016+) [^x86_32-floats-return-ABI]
 `i686-pc-windows-msvc` | 32-bit MSVC (Windows 10+, Windows Server 2016+) [^x86_32-floats-return-ABI]
 `i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+) [^x86_32-floats-return-ABI]
@@ -86,7 +87,6 @@ so Rustup may install the documentation for a similar tier 1 target instead.
 
 target | notes
 -------|-------
-[`aarch64-apple-darwin`](platform-support/apple-darwin.md) | ARM64 macOS (11.0+, Big Sur+)
 `aarch64-pc-windows-msvc` | ARM64 Windows MSVC
 `aarch64-unknown-linux-musl` | ARM64 Linux with musl 1.2.3
 `arm-unknown-linux-gnueabi` | Armv6 Linux (kernel 3.2, glibc 2.17)
@@ -97,7 +97,8 @@ target | notes
 `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)
-`riscv64gc-unknown-linux-gnu` | RISC-V Linux (kernel 4.20, glibc 2.29)
+[`riscv64gc-unknown-linux-gnu`](platform-support/riscv64gc-unknown-linux-gnu.md) | RISC-V Linux (kernel 4.20, glibc 2.29)
+[`riscv64gc-unknown-linux-musl`](platform-support/riscv64gc-unknown-linux-musl.md) | RISC-V Linux (kernel 4.20, musl 1.2.3)
 `s390x-unknown-linux-gnu` | S390x Linux (kernel 3.2, glibc 2.17)
 `x86_64-unknown-freebsd` | 64-bit FreeBSD
 `x86_64-unknown-illumos` | illumos
@@ -263,7 +264,7 @@ target | std | host | notes
 [`aarch64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | ARM64 OpenBSD
 [`aarch64-unknown-redox`](platform-support/redox.md) | ✓ |  | ARM64 Redox OS
 `aarch64-uwp-windows-msvc` | ✓ |  |
-`aarch64-wrs-vxworks` | ? |  |
+[`aarch64-wrs-vxworks`](platform-support/vxworks.md) | ✓ |  | ARM64 VxWorks OS
 `aarch64_be-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (big-endian, ILP32 ABI)
 `aarch64_be-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (big-endian)
 [`aarch64_be-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD (big-endian)
@@ -281,7 +282,7 @@ target | std | host | notes
 [`armv7-unknown-linux-uclibceabihf`](platform-support/armv7-unknown-linux-uclibceabihf.md) | ✓ | ? | Armv7-A Linux with uClibc, hardfloat
 `armv7-unknown-freebsd` | ✓ | ✓ | Armv7-A FreeBSD
 [`armv7-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | Armv7-A NetBSD w/hard-float
-`armv7-wrs-vxworks-eabihf` | ? |  | Armv7-A for VxWorks
+[`armv7-wrs-vxworks-eabihf`](platform-support/vxworks.md) | ✓ |  | Armv7-A for VxWorks
 [`armv7a-kmc-solid_asp3-eabi`](platform-support/kmc-solid.md) | ✓ |  | ARM SOLID with TOPPERS/ASP3
 [`armv7a-kmc-solid_asp3-eabihf`](platform-support/kmc-solid.md) | ✓ |  | ARM SOLID with TOPPERS/ASP3, hardfloat
 [`armv7a-none-eabihf`](platform-support/arm-none-eabi.md) | * |  | Bare Armv7-A, hardfloat
@@ -307,7 +308,7 @@ target | std | host | notes
 `i686-uwp-windows-gnu` | ✓ |  | [^x86_32-floats-return-ABI]
 `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]
+[`i686-wrs-vxworks`](platform-support/vxworks.md) | ✓ |  | [^x86_32-floats-return-ABI]
 [`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
@@ -333,13 +334,13 @@ target | std | host | notes
 `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`](platform-support/powerpc-unknown-openbsd.md) | * |  |
-`powerpc-wrs-vxworks-spe` | ? |  |
-`powerpc-wrs-vxworks` | ? |  |
+[`powerpc-wrs-vxworks-spe`](platform-support/vxworks.md) | ✓ |  |
+[`powerpc-wrs-vxworks`](platform-support/vxworks.md) | ✓ |  |
 `powerpc64-unknown-freebsd` | ✓ | ✓ | PPC64 FreeBSD (ELFv1 and ELFv2)
 `powerpc64le-unknown-freebsd` |   |   | PPC64LE FreeBSD
 `powerpc-unknown-freebsd` |   |   | PowerPC FreeBSD
 `powerpc64-unknown-linux-musl` | ? |  | 64-bit PowerPC Linux with musl 1.2.3
-`powerpc64-wrs-vxworks` | ? |  |
+[`powerpc64-wrs-vxworks`](platform-support/vxworks.md) | ✓ |  |
 `powerpc64le-unknown-linux-musl` | ? |  | 64-bit PowerPC Linux with musl 1.2.3, Little Endian
 [`powerpc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/powerpc64
 [`powerpc64-ibm-aix`](platform-support/aix.md) | ? |  | 64-bit AIX (7.2 and newer)
@@ -354,7 +355,6 @@ target | std | host | notes
 [`riscv64gc-unknown-hermit`](platform-support/hermit.md) | ✓ |   | RISC-V Hermit
 `riscv64gc-unknown-freebsd` |   |   | RISC-V FreeBSD
 `riscv64gc-unknown-fuchsia` |   |   | RISC-V Fuchsia
-`riscv64gc-unknown-linux-musl` |   |   | RISC-V Linux (kernel 4.20, musl 1.2.3)
 [`riscv64gc-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | RISC-V NetBSD
 [`riscv64gc-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/riscv64
 [`riscv64-linux-android`](platform-support/android.md) |   |   | RISC-V 64-bit Android
@@ -383,7 +383,7 @@ target | std | host | notes
 `x86_64-uwp-windows-gnu` | ✓ |  |
 `x86_64-uwp-windows-msvc` | ✓ |  |
 [`x86_64-win7-windows-msvc`](platform-support/win7-windows-msvc.md) | ✓ |   | 64-bit Windows 7 support
-`x86_64-wrs-vxworks` | ? |  |
+[`x86_64-wrs-vxworks`](platform-support/vxworks.md) | ✓ |  |
 [`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`](platform-support/xtensa.md) | * |  | Xtensa ESP32
diff --git a/src/doc/rustc/src/platform-support/apple-darwin.md b/src/doc/rustc/src/platform-support/apple-darwin.md
index 0fb86949a4b..c3a7b81f411 100644
--- a/src/doc/rustc/src/platform-support/apple-darwin.md
+++ b/src/doc/rustc/src/platform-support/apple-darwin.md
@@ -5,9 +5,6 @@ Apple macOS targets.
 **Tier: 1**
 
 - `x86_64-apple-darwin`: macOS on 64-bit x86.
-
-**Tier: 2 (with Host Tools)**
-
 - `aarch64-apple-darwin`: macOS on ARM64 (M1-family or later Apple Silicon CPUs).
 
 ## Target maintainers
diff --git a/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-gnu.md b/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-gnu.md
new file mode 100644
index 00000000000..1acc0584be9
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-gnu.md
@@ -0,0 +1,129 @@
+# `riscv64gc-unknown-linux-gnu`
+
+**Tier: 2 (with Host Tools)**
+
+RISC-V targets using the *RV64I* base instruction set with the *G* collection of extensions, as well as the *C* extension.
+
+
+## Target maintainers
+
+- Kito Cheng, <kito.cheng@gmail.com>, [@kito-cheng](https://github.com/kito-cheng)
+- Michael Maitland, <michaeltmaitland@gmail.com>, [@michaelmaitland](https://github.com/michaelmaitland)
+- Robin Randhawa, <robin.randhawa@sifive.com>, [@robin-randhawa-sifive](https://github.com/robin-randhawa-sifive)
+- Craig Topper, <craig.topper@sifive.com>, [@topperc](https://github.com/topperc)
+
+## Requirements
+
+This target requires:
+
+* Linux Kernel version 4.20 or later
+* glibc 2.17 or later
+
+
+## Building the target
+
+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
+enabled in `config.toml`. For example:
+
+```toml
+[build]
+target = ["riscv64gc-unknown-linux-gnu"]
+```
+
+
+## Building Rust programs
+
+
+On a RISC-V host, the `riscv64gc-unknown-linux-gnu` target should be automatically
+installed and used by default.
+
+On a non-RISC-V host, add the target:
+
+```bash
+rustup target add riscv64gc-unknown-linux-gnu
+```
+
+Then cross compile crates with:
+
+```bash
+cargo build --target riscv64gc-unknown-linux-gnu
+```
+
+
+## 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
+toolchains and C code"
+section below.
+
+
+## Cross-compilation toolchains and C code
+
+A RISC-V toolchain can be obtained for Windows/Mac/Linux from the
+[`riscv-gnu-toolchain`](https://github.com/riscv-collab/riscv-gnu-toolchain)
+repostory. Binaries are available via
+[embecosm](https://www.embecosm.com/resources/tool-chain-downloads/#riscv-linux),
+and may also be available from your OS's package manager.
+
+On Ubuntu, a RISC-V toolchain can be installed with:
+
+```bash
+apt install gcc-riscv64-linux-gnu g++-riscv64-linux-gnu libc6-dev-riscv64-cross
+```
+
+Depending on your system, you may need to configure the target to use the GNU
+GCC linker. To use it, add the following to your `.cargo/config.toml`:
+
+```toml
+[target.riscv64gc-unknown-linux-gnu]
+linker = "riscv64-linux-gnu-gcc"
+```
+
+If your `riscv64-linux-gnu-*` toolchain is not in your `PATH` you may need to
+configure additional settings:
+
+```toml
+[target.riscv64gc-unknown-linux-gnu]
+# Adjust the paths to point at your toolchain
+cc = "/TOOLCHAIN_PATH/bin/riscv64-linux-gnu-gcc"
+cxx = "/TOOLCHAIN_PATH/bin/riscv64-linux-gnu-g++"
+ar = "/TOOLCHAIN_PATH/bin/riscv64-linux-gnu-ar"
+ranlib = "/TOOLCHAIN_PATH/bin/riscv64-linux-gnu-ranlib"
+linker = "/TOOLCHAIN_PATH/bin/riscv64-linux-gnu-gcc"
+```
+
+To test cross compiled binaries on a non-RISCV-V host, you can use
+[`qemu`](https://www.qemu.org/docs/master/system/target-riscv.html).
+On Ubuntu, a RISC-V emulator can be obtained with:
+
+```bash
+apt install qemu-system-riscv64
+```
+
+Then, in `.cargo/config.toml` set the `runner`:
+
+```toml
+[target.riscv64gc-unknown-linux-gnu]
+runner = "qemu-riscv64-static -L /usr/riscv64-linux-gnu -cpu rv64"
+```
+
+On Mac and Linux, it's also possible to use
+[`lima`](https://github.com/lima-vm/lima) to emulate RISC-V in a similar way to
+how WSL2 works on Windows:
+
+```bash
+limactl start template://riscv
+limactl shell riscv
+```
+
+Using [Docker (with BuildKit)](https://docs.docker.com/build/buildkit/) the
+[`riscv64/ubuntu`](https://hub.docker.com/r/riscv64/ubuntu) image can be used
+to buiild or run `riscv64gc-unknown-linux-gnu` binaries.
+
+```bash
+docker run --platform linux/riscv64 -ti --rm --mount "type=bind,src=$(pwd),dst=/checkout" riscv64/ubuntu bash
+```
diff --git a/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-musl.md b/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-musl.md
new file mode 100644
index 00000000000..5b3dc683038
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-musl.md
@@ -0,0 +1,47 @@
+# riscv64gc-unknown-linux-musl
+
+**Tier: 2**
+
+Target for RISC-V Linux programs using musl libc.
+
+## Target maintainers
+
+- [@Amanieu](https://github.com/Amanieu)
+- [@kraj](https://github.com/kraj)
+
+## Requirements
+
+Building the target itself requires a RISC-V compiler that is supported by `cc-rs`.
+
+## Building the target
+
+The target can be built by enabling it for a `rustc` build.
+
+```toml
+[build]
+target = ["riscv64gc-unknown-linux-musl"]
+```
+
+Make sure your C compiler is included in `$PATH`, then add it to the `config.toml`:
+
+```toml
+[target.riscv64gc-unknown-linux-musl]
+cc = "riscv64-linux-gnu-gcc"
+cxx = "riscv64-linux-gnu-g++"
+ar = "riscv64-linux-gnu-ar"
+linker = "riscv64-linux-gnu-gcc"
+```
+
+## Building Rust programs
+
+This target are distributed through `rustup`, and otherwise require no
+special configuration.
+
+## Cross-compilation
+
+This target can be cross-compiled from any host.
+
+## Testing
+
+This target can be tested as normal with `x.py` on a RISC-V host or via QEMU
+emulation.
diff --git a/src/doc/rustc/src/platform-support/vxworks.md b/src/doc/rustc/src/platform-support/vxworks.md
new file mode 100644
index 00000000000..f1860346c8f
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/vxworks.md
@@ -0,0 +1,59 @@
+# `*-wrs-vxworks`
+
+**Tier: 3**
+
+Targets for the VxWorks operating
+system.
+
+Target triplets available:
+
+- `x86_64-wrs-vxworks`
+- `aarch64-wrs-vxworks`
+- `i686-wrs-vxworks`
+- `armv7-wrs-vxworks-eabihf`
+- `powerpc-wrs-vxworks`
+- `powerpc64-wrs-vxworks`
+- `powerpc-wrs-vxworks-spe`
+
+## Target maintainers
+
+- B I Mohammed Abbas ([@biabbas](https://github.com/biabbas))
+
+## Requirements
+
+### OS version
+
+The minimum supported version is VxWorks 7.
+
+## Building
+
+Rust for each target can be cross-compiled with its specific target vsb configuration. Std support is added but not yet fully tested.
+
+## Building the target
+
+You can build Rust with support for the targets by adding it to the `target` list in `config.toml`. In addition the workbench and wr-cc have to configured and activated.
+
+```toml
+[build]
+build-stage = 1
+target = [
+    "<HOST_TARGET>",
+    "x86_64-wrs-vxworks",
+    "aarch64-wrs-vxworks",
+    "i686-wrs-vxworks",
+    "armv7-wrs-vxworks-eabihf",
+    "powerpc-wrs-vxworks",
+    "powerpc64-wrs-vxworks",
+    "powerpc-wrs-vxworks-spe",
+]
+```
+
+## Building Rust programs
+
+Rust does not yet ship pre-compiled artifacts for VxWorks.
+
+The easiest way to build and test programs for VxWorks is to use the shipped rustc and cargo in VxWorks workbench, following the official windriver guidelines.
+
+## Cross-compilation toolchains and C code
+
+The target supports C code. Pre-compiled C toolchains can be found in provided VxWorks workbench.
diff --git a/src/doc/unstable-book/src/language-features/rustc-private.md b/src/doc/unstable-book/src/language-features/rustc-private.md
new file mode 100644
index 00000000000..97fce5980e4
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/rustc-private.md
@@ -0,0 +1,11 @@
+# `rustc_private`
+
+The tracking issue for this feature is: [#27812]
+
+[#27812]: https://github.com/rust-lang/rust/issues/27812
+
+------------------------
+
+This feature allows access to unstable internal compiler crates.
+
+Additionally it changes the linking behavior of crates which have this feature enabled. It will prevent linking to a dylib if there's a static variant of it already statically linked into another dylib dependency. This is required to successfully link to `rustc_driver`.
diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish
index 805fc8aa8cc..297dc11cd61 100644
--- a/src/etc/completions/x.py.fish
+++ b/src/etc/completions/x.py.fish
@@ -266,7 +266,7 @@ complete -c x.py -n "__fish_seen_subcommand_from doc" -l enable-bolt-settings -d
 complete -c x.py -n "__fish_seen_subcommand_from doc" -l skip-stage0-validation -d 'Skip stage0 compiler validation'
 complete -c x.py -n "__fish_seen_subcommand_from doc" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x.py -n "__fish_seen_subcommand_from test" -l test-args -d 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)' -r
-complete -c x.py -n "__fish_seen_subcommand_from test" -l rustc-args -d 'extra options to pass the compiler when running tests' -r
+complete -c x.py -n "__fish_seen_subcommand_from test" -l compiletest-rustc-args -d 'extra options to pass the compiler when running compiletest tests' -r
 complete -c x.py -n "__fish_seen_subcommand_from test" -l extra-checks -d 'comma-separated list of other files types to check (accepts py, py:lint, py:fmt, shell)' -r
 complete -c x.py -n "__fish_seen_subcommand_from test" -l compare-mode -d 'mode describing what file the actual ui output will be compared to' -r
 complete -c x.py -n "__fish_seen_subcommand_from test" -l pass -d 'force {check,build,run}-pass tests to this mode' -r
@@ -313,7 +313,6 @@ complete -c x.py -n "__fish_seen_subcommand_from test" -l enable-bolt-settings -
 complete -c x.py -n "__fish_seen_subcommand_from test" -l skip-stage0-validation -d 'Skip stage0 compiler validation'
 complete -c x.py -n "__fish_seen_subcommand_from test" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x.py -n "__fish_seen_subcommand_from miri" -l test-args -d 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)' -r
-complete -c x.py -n "__fish_seen_subcommand_from miri" -l rustc-args -d 'extra options to pass the compiler when running tests' -r
 complete -c x.py -n "__fish_seen_subcommand_from miri" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from miri" -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 miri" -l build -d 'build target of the stage0 compiler' -r -f
diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1
index ce590d2fa48..4b424471a26 100644
--- a/src/etc/completions/x.py.ps1
+++ b/src/etc/completions/x.py.ps1
@@ -338,7 +338,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
         }
         'x.py;test' {
             [CompletionResult]::new('--test-args', 'test-args', [CompletionResultType]::ParameterName, 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)')
-            [CompletionResult]::new('--rustc-args', 'rustc-args', [CompletionResultType]::ParameterName, 'extra options to pass the compiler when running tests')
+            [CompletionResult]::new('--compiletest-rustc-args', 'compiletest-rustc-args', [CompletionResultType]::ParameterName, 'extra options to pass the compiler when running compiletest tests')
             [CompletionResult]::new('--extra-checks', 'extra-checks', [CompletionResultType]::ParameterName, 'comma-separated list of other files types to check (accepts py, py:lint, py:fmt, shell)')
             [CompletionResult]::new('--compare-mode', 'compare-mode', [CompletionResultType]::ParameterName, 'mode describing what file the actual ui output will be compared to')
             [CompletionResult]::new('--pass', 'pass', [CompletionResultType]::ParameterName, 'force {check,build,run}-pass tests to this mode')
@@ -392,7 +392,6 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
         }
         'x.py;miri' {
             [CompletionResult]::new('--test-args', 'test-args', [CompletionResultType]::ParameterName, 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)')
-            [CompletionResult]::new('--rustc-args', 'rustc-args', [CompletionResultType]::ParameterName, 'extra options to pass the compiler when running tests')
             [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')
diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh
index a4234905476..60ba8d3ba70 100644
--- a/src/etc/completions/x.py.sh
+++ b/src/etc/completions/x.py.sh
@@ -1300,7 +1300,7 @@ _x.py() {
             return 0
             ;;
         x.py__miri)
-            opts="-v -i -j -h --no-fail-fast --test-args --rustc-args --no-doc --doc --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]..."
+            opts="-v -i -j -h --no-fail-fast --test-args --no-doc --doc --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
@@ -1310,10 +1310,6 @@ _x.py() {
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
-                --rustc-args)
-                    COMPREPLY=($(compgen -f "${cur}"))
-                    return 0
-                    ;;
                 --config)
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
@@ -1862,7 +1858,7 @@ _x.py() {
             return 0
             ;;
         x.py__test)
-            opts="-v -i -j -h --no-fail-fast --test-args --rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --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]..."
+            opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --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
@@ -1872,7 +1868,7 @@ _x.py() {
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
-                --rustc-args)
+                --compiletest-rustc-args)
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh
index fc8be4f7881..688f692da24 100644
--- a/src/etc/completions/x.py.zsh
+++ b/src/etc/completions/x.py.zsh
@@ -337,7 +337,7 @@ _arguments "${_arguments_options[@]}" \
 (test)
 _arguments "${_arguments_options[@]}" \
 '*--test-args=[extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)]:ARGS: ' \
-'*--rustc-args=[extra options to pass the compiler when running tests]:ARGS: ' \
+'*--compiletest-rustc-args=[extra options to pass the compiler when running compiletest tests]:ARGS: ' \
 '--extra-checks=[comma-separated list of other files types to check (accepts py, py\:lint, py\:fmt, shell)]:EXTRA_CHECKS: ' \
 '--compare-mode=[mode describing what file the actual ui output will be compared to]:COMPARE MODE: ' \
 '--pass=[force {check,build,run}-pass tests to this mode]:check | build | run: ' \
@@ -393,7 +393,6 @@ _arguments "${_arguments_options[@]}" \
 (miri)
 _arguments "${_arguments_options[@]}" \
 '*--test-args=[extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)]:ARGS: ' \
-'*--rustc-args=[extra options to pass the compiler when running tests]:ARGS: ' \
 '--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:( )' \
diff --git a/src/etc/gdb_providers.py b/src/etc/gdb_providers.py
index 227695cdadd..e8f9dee07d3 100644
--- a/src/etc/gdb_providers.py
+++ b/src/etc/gdb_providers.py
@@ -56,7 +56,7 @@ class StdStringProvider(printer_base):
         self._valobj = valobj
         vec = valobj["vec"]
         self._length = int(vec["len"])
-        self._data_ptr = unwrap_unique_or_non_null(vec["buf"]["ptr"])
+        self._data_ptr = unwrap_unique_or_non_null(vec["buf"]["inner"]["ptr"])
 
     def to_string(self):
         return self._data_ptr.lazy_string(encoding="utf-8", length=self._length)
@@ -74,7 +74,7 @@ class StdOsStringProvider(printer_base):
         vec = buf[ZERO_FIELD] if is_windows else buf
 
         self._length = int(vec["len"])
-        self._data_ptr = unwrap_unique_or_non_null(vec["buf"]["ptr"])
+        self._data_ptr = unwrap_unique_or_non_null(vec["buf"]["inner"]["ptr"])
 
     def to_string(self):
         return self._data_ptr.lazy_string(encoding="utf-8", length=self._length)
@@ -96,6 +96,7 @@ class StdStrProvider(printer_base):
     def display_hint():
         return "string"
 
+
 def _enumerate_array_elements(element_ptrs):
     for (i, element_ptr) in enumerate(element_ptrs):
         key = "[{}]".format(i)
@@ -112,6 +113,7 @@ def _enumerate_array_elements(element_ptrs):
 
         yield key, element
 
+
 class StdSliceProvider(printer_base):
     def __init__(self, valobj):
         self._valobj = valobj
@@ -130,11 +132,14 @@ class StdSliceProvider(printer_base):
     def display_hint():
         return "array"
 
+
 class StdVecProvider(printer_base):
     def __init__(self, valobj):
         self._valobj = valobj
         self._length = int(valobj["len"])
-        self._data_ptr = unwrap_unique_or_non_null(valobj["buf"]["ptr"])
+        self._data_ptr = unwrap_unique_or_non_null(valobj["buf"]["inner"]["ptr"])
+        ptr_ty = gdb.Type.pointer(valobj.type.template_argument(0))
+        self._data_ptr = self._data_ptr.reinterpret_cast(ptr_ty)
 
     def to_string(self):
         return "Vec(size={})".format(self._length)
@@ -155,11 +160,13 @@ class StdVecDequeProvider(printer_base):
         self._head = int(valobj["head"])
         self._size = int(valobj["len"])
         # BACKCOMPAT: rust 1.75
-        cap = valobj["buf"]["cap"]
+        cap = valobj["buf"]["inner"]["cap"]
         if cap.type.code != gdb.TYPE_CODE_INT:
             cap = cap[ZERO_FIELD]
         self._cap = int(cap)
-        self._data_ptr = unwrap_unique_or_non_null(valobj["buf"]["ptr"])
+        self._data_ptr = unwrap_unique_or_non_null(valobj["buf"]["inner"]["ptr"])
+        ptr_ty = gdb.Type.pointer(valobj.type.template_argument(0))
+        self._data_ptr = self._data_ptr.reinterpret_cast(ptr_ty)
 
     def to_string(self):
         return "VecDeque(size={})".format(self._size)
diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py
index c6330117380..8750d7682d1 100644
--- a/src/etc/lldb_providers.py
+++ b/src/etc/lldb_providers.py
@@ -389,11 +389,11 @@ class StdVecSyntheticProvider:
     def update(self):
         # type: () -> None
         self.length = self.valobj.GetChildMemberWithName("len").GetValueAsUnsigned()
-        self.buf = self.valobj.GetChildMemberWithName("buf")
+        self.buf = self.valobj.GetChildMemberWithName("buf").GetChildMemberWithName("inner")
 
         self.data_ptr = unwrap_unique_or_non_null(self.buf.GetChildMemberWithName("ptr"))
 
-        self.element_type = self.data_ptr.GetType().GetPointeeType()
+        self.element_type = self.valobj.GetType().GetTemplateArgumentType(0)
         self.element_type_size = self.element_type.GetByteSize()
 
     def has_children(self):
@@ -474,7 +474,7 @@ class StdVecDequeSyntheticProvider:
         # type: () -> None
         self.head = self.valobj.GetChildMemberWithName("head").GetValueAsUnsigned()
         self.size = self.valobj.GetChildMemberWithName("len").GetValueAsUnsigned()
-        self.buf = self.valobj.GetChildMemberWithName("buf")
+        self.buf = self.valobj.GetChildMemberWithName("buf").GetChildMemberWithName("inner")
         cap = self.buf.GetChildMemberWithName("cap")
         if cap.GetType().num_fields == 1:
             cap = cap.GetChildAtIndex(0)
@@ -482,7 +482,7 @@ class StdVecDequeSyntheticProvider:
 
         self.data_ptr = unwrap_unique_or_non_null(self.buf.GetChildMemberWithName("ptr"))
 
-        self.element_type = self.data_ptr.GetType().GetPointeeType()
+        self.element_type = self.valobj.GetType().GetTemplateArgumentType(0)
         self.element_type_size = self.element_type.GetByteSize()
 
     def has_children(self):
diff --git a/src/etc/natvis/liballoc.natvis b/src/etc/natvis/liballoc.natvis
index da307809f7b..49d82dfad82 100644
--- a/src/etc/natvis/liballoc.natvis
+++ b/src/etc/natvis/liballoc.natvis
@@ -4,10 +4,10 @@
     <DisplayString>{{ len={len} }}</DisplayString>
     <Expand>
       <Item Name="[len]" ExcludeView="simple">len</Item>
-      <Item Name="[capacity]" ExcludeView="simple">buf.cap.__0</Item>
+      <Item Name="[capacity]" ExcludeView="simple">buf.inner.cap.__0</Item>
       <ArrayItems>
         <Size>len</Size>
-        <ValuePointer>buf.ptr.pointer.pointer</ValuePointer>
+        <ValuePointer>($T1*)buf.inner.ptr.pointer.pointer</ValuePointer>
       </ArrayItems>
     </Expand>
   </Type>
@@ -15,7 +15,7 @@
     <DisplayString>{{ len={len} }}</DisplayString>
     <Expand>
       <Item Name="[len]" ExcludeView="simple">len</Item>
-      <Item Name="[capacity]" ExcludeView="simple">buf.cap.__0</Item>
+      <Item Name="[capacity]" ExcludeView="simple">buf.inner.cap.__0</Item>
       <CustomListItems>
         <Variable Name="i" InitialValue="0" />
         <Size>len</Size>
@@ -23,7 +23,7 @@
           <If Condition="i == len">
             <Break/>
           </If>
-          <Item>buf.ptr.pointer.pointer[(i + head) % buf.cap.__0]</Item>
+          <Item>(($T1*)buf.inner.ptr.pointer.pointer)[(i + head) % buf.inner.cap.__0]</Item>
           <Exec>i = i + 1</Exec>
         </Loop>
       </CustomListItems>
@@ -41,17 +41,17 @@
     </Expand>
   </Type>
   <Type Name="alloc::string::String">
-    <DisplayString>{(char*)vec.buf.ptr.pointer.pointer,[vec.len]s8}</DisplayString>
-    <StringView>(char*)vec.buf.ptr.pointer.pointer,[vec.len]s8</StringView>
+    <DisplayString>{(char*)vec.buf.inner.ptr.pointer.pointer,[vec.len]s8}</DisplayString>
+    <StringView>(char*)vec.buf.inner.ptr.pointer.pointer,[vec.len]s8</StringView>
     <Expand>
       <Item Name="[len]" ExcludeView="simple">vec.len</Item>
-      <Item Name="[capacity]" ExcludeView="simple">vec.buf.cap.__0</Item>
+      <Item Name="[capacity]" ExcludeView="simple">vec.buf.inner.cap.__0</Item>
       <Synthetic Name="[chars]">
-        <DisplayString>{(char*)vec.buf.ptr.pointer.pointer,[vec.len]s8}</DisplayString>
+        <DisplayString>{(char*)vec.buf.inner.ptr.pointer.pointer,[vec.len]s8}</DisplayString>
         <Expand>
           <ArrayItems>
             <Size>vec.len</Size>
-            <ValuePointer>(char*)vec.buf.ptr.pointer.pointer</ValuePointer>
+            <ValuePointer>(char*)vec.buf.inner.ptr.pointer.pointer</ValuePointer>
           </ArrayItems>
         </Expand>
       </Synthetic>
diff --git a/src/etc/natvis/libstd.natvis b/src/etc/natvis/libstd.natvis
index 4371b995318..4719a479c47 100644
--- a/src/etc/natvis/libstd.natvis
+++ b/src/etc/natvis/libstd.natvis
@@ -104,14 +104,14 @@
   </Type>
 
   <Type Name="std::ffi::os_str::OsString">
-    <DisplayString>{(char*)inner.inner.bytes.buf.ptr.pointer.pointer,[inner.inner.bytes.len]}</DisplayString>
+    <DisplayString>{(char*)inner.inner.bytes.buf.inner.ptr.pointer.pointer,[inner.inner.bytes.len]}</DisplayString>
     <Expand>
       <Synthetic Name="[chars]">
-        <DisplayString>{(char*)inner.inner.bytes.buf.ptr.pointer.pointer,[inner.inner.bytes.len]}</DisplayString>
+        <DisplayString>{(char*)inner.inner.bytes.buf.inner.ptr.pointer.pointer,[inner.inner.bytes.len]}</DisplayString>
         <Expand>
           <ArrayItems>
             <Size>inner.inner.bytes.len</Size>
-            <ValuePointer>(char*)inner.inner.bytes.buf.ptr.pointer.pointer</ValuePointer>
+            <ValuePointer>(char*)inner.inner.bytes.buf.inner.ptr.pointer.pointer</ValuePointer>
           </ArrayItems>
         </Expand>
       </Synthetic>
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index fe531f0ff59..b3fccbf6456 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -8,7 +8,7 @@ path = "lib.rs"
 
 [dependencies]
 arrayvec = { version = "0.7", default-features = false }
-rinja = { version = "0.2", default-features = false, features = ["config"] }
+rinja = { version = "0.3", default-features = false, features = ["config"] }
 base64 = "0.21.7"
 itertools = "0.12"
 indexmap = "2"
@@ -23,6 +23,7 @@ tempfile = "3"
 tracing = "0.1"
 tracing-tree = "0.3.0"
 threadpool = "1.8.1"
+unicode-segmentation = "1.9"
 
 [dependencies.tracing-subscriber]
 version = "0.3.3"
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index ac927e9a194..f46ffea830e 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -6,13 +6,11 @@ use rustc_middle::ty::{self, Region, Ty};
 use rustc_span::def_id::DefId;
 use rustc_span::symbol::{kw, Symbol};
 use rustc_trait_selection::traits::auto_trait::{self, RegionTarget};
-
 use thin_vec::ThinVec;
 
-use crate::clean::{self, simplify, Lifetime};
 use crate::clean::{
-    clean_generic_param_def, clean_middle_ty, clean_predicate, clean_trait_ref_with_constraints,
-    clean_ty_generics,
+    self, clean_generic_param_def, clean_middle_ty, clean_predicate,
+    clean_trait_ref_with_constraints, clean_ty_generics, simplify, Lifetime,
 };
 use crate::core::DocContext;
 
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index 4c7a2ecdb53..48c3fb65203 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -5,7 +5,6 @@ use rustc_middle::ty::{self, Upcast};
 use rustc_span::def_id::DefId;
 use rustc_span::DUMMY_SP;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
-
 use thin_vec::ThinVec;
 
 use crate::clean;
diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs
index 2814e83dcd7..fb9754c7ffc 100644
--- a/src/librustdoc/clean/cfg.rs
+++ b/src/librustdoc/clean/cfg.rs
@@ -4,15 +4,13 @@
 // switch to use those structures instead.
 
 use std::fmt::{self, Write};
-use std::mem;
-use std::ops;
+use std::{mem, ops};
 
 use rustc_ast::{LitKind, MetaItem, MetaItemKind, NestedMetaItem};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_feature::Features;
 use rustc_session::parse::ParseSess;
 use rustc_span::symbol::{sym, Symbol};
-
 use rustc_span::Span;
 
 use crate::html::escape::Escape;
diff --git a/src/librustdoc/clean/cfg/tests.rs b/src/librustdoc/clean/cfg/tests.rs
index 2857f74c744..a9b3abadb20 100644
--- a/src/librustdoc/clean/cfg/tests.rs
+++ b/src/librustdoc/clean/cfg/tests.rs
@@ -1,11 +1,10 @@
-use super::*;
-
 use rustc_ast::{MetaItemLit, Path, Safety, StrStyle};
-use rustc_span::create_default_session_globals_then;
 use rustc_span::symbol::{kw, Ident};
-use rustc_span::DUMMY_SP;
+use rustc_span::{create_default_session_globals_then, DUMMY_SP};
 use thin_vec::thin_vec;
 
+use super::*;
+
 fn word_cfg(s: &str) -> Cfg {
     Cfg::Cfg(Symbol::intern(s), None)
 }
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 0024e246ef0..f8953f0ebcf 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -3,11 +3,7 @@
 use std::iter::once;
 use std::sync::Arc;
 
-use thin_vec::{thin_vec, ThinVec};
-
-use rustc_ast as ast;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, DefIdSet, LocalModDefId};
 use rustc_hir::Mutability;
@@ -16,8 +12,11 @@ use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::hygiene::MacroKind;
-use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_span::symbol::{sym, Symbol};
+use thin_vec::{thin_vec, ThinVec};
+use {rustc_ast as ast, rustc_hir as hir};
 
+use super::Item;
 use crate::clean::{
     self, clean_bound_vars, clean_generics, clean_impl_item, clean_middle_assoc_item,
     clean_middle_field, clean_middle_ty, clean_poly_fn_sig, clean_trait_ref_with_constraints,
@@ -27,8 +26,6 @@ use crate::clean::{
 use crate::core::DocContext;
 use crate::formats::item_type::ItemType;
 
-use super::Item;
-
 /// Attempt to inline a definition into this AST.
 ///
 /// This function will fetch the definition specified, and if it is
@@ -131,8 +128,8 @@ pub(crate) fn try_inline(
         Res::Def(DefKind::Const, did) => {
             record_extern_fqn(cx, did, ItemType::Constant);
             cx.with_param_env(did, |cx| {
-                let (generics, ty, ct) = build_const_item(cx, did);
-                clean::ConstantItem(generics, Box::new(ty), ct)
+                let ct = build_const_item(cx, did);
+                clean::ConstantItem(Box::new(ct))
             })
         }
         Res::Def(DefKind::Macro(kind), did) => {
@@ -720,10 +717,7 @@ pub(crate) fn print_inlined_const(tcx: TyCtxt<'_>, did: DefId) -> String {
     }
 }
 
-fn build_const_item(
-    cx: &mut DocContext<'_>,
-    def_id: DefId,
-) -> (clean::Generics, clean::Type, clean::Constant) {
+fn build_const_item(cx: &mut DocContext<'_>, def_id: DefId) -> clean::Constant {
     let mut generics =
         clean_ty_generics(cx, cx.tcx.generics_of(def_id), cx.tcx.explicit_predicates_of(def_id));
     clean::simplify::move_bounds_to_generic_parameters(&mut generics);
@@ -733,17 +727,17 @@ fn build_const_item(
         None,
         None,
     );
-    (generics, ty, clean::Constant { kind: clean::ConstantKind::Extern { def_id } })
+    clean::Constant { generics, type_: ty, kind: clean::ConstantKind::Extern { def_id } }
 }
 
 fn build_static(cx: &mut DocContext<'_>, did: DefId, mutable: bool) -> clean::Static {
     clean::Static {
-        type_: clean_middle_ty(
+        type_: Box::new(clean_middle_ty(
             ty::Binder::dummy(cx.tcx.type_of(did).instantiate_identity()),
             cx,
             Some(did),
             None,
-        ),
+        )),
         mutability: if mutable { Mutability::Mut } else { Mutability::Not },
         expr: None,
     }
@@ -798,11 +792,7 @@ fn build_macro(
 fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean::Generics {
     for pred in &mut g.where_predicates {
         match *pred {
-            clean::WherePredicate::BoundPredicate {
-                ty: clean::Generic(ref s),
-                ref mut bounds,
-                ..
-            } if *s == kw::SelfUpper => {
+            clean::WherePredicate::BoundPredicate { ty: clean::SelfTy, ref mut bounds, .. } => {
                 bounds.retain(|bound| match bound {
                     clean::GenericBound::TraitBound(clean::PolyTrait { trait_, .. }, _) => {
                         trait_.def_id() != trait_did
@@ -818,13 +808,13 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean:
         clean::WherePredicate::BoundPredicate {
             ty:
                 clean::QPath(box clean::QPathData {
-                    self_type: clean::Generic(ref s),
+                    self_type: clean::Generic(_),
                     trait_: Some(trait_),
                     ..
                 }),
             bounds,
             ..
-        } => !(bounds.is_empty() || *s == kw::SelfUpper && trait_.def_id() == trait_did),
+        } => !bounds.is_empty() && trait_.def_id() != trait_did,
         _ => true,
     });
     g
@@ -838,9 +828,7 @@ fn separate_supertrait_bounds(
 ) -> (clean::Generics, Vec<clean::GenericBound>) {
     let mut ty_bounds = Vec::new();
     g.where_predicates.retain(|pred| match *pred {
-        clean::WherePredicate::BoundPredicate { ty: clean::Generic(ref s), ref bounds, .. }
-            if *s == kw::SelfUpper =>
-        {
+        clean::WherePredicate::BoundPredicate { ty: clean::SelfTy, ref bounds, .. } => {
             ty_bounds.extend(bounds.iter().cloned());
             false
         }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 26011926cdd..cffadc7c10a 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -30,41 +30,36 @@ mod simplify;
 pub(crate) mod types;
 pub(crate) mod utils;
 
-use rustc_ast as ast;
+use std::borrow::Cow;
+use std::collections::BTreeMap;
+use std::mem;
+
 use rustc_ast::token::{Token, TokenKind};
 use rustc_ast::tokenstream::{TokenStream, TokenTree};
-use rustc_attr as attr;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet, IndexEntry};
-use rustc_errors::{codes::*, struct_span_code_err, FatalError};
-use rustc_hir as hir;
+use rustc_errors::codes::*;
+use rustc_errors::{struct_span_code_err, FatalError};
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId, LOCAL_CRATE};
 use rustc_hir::PredicateOrigin;
 use rustc_hir_analysis::lower_ty;
 use rustc_middle::metadata::Reexport;
 use rustc_middle::middle::resolve_bound_vars as rbv;
-use rustc_middle::ty::GenericArgsRef;
-use rustc_middle::ty::TypeVisitableExt;
-use rustc_middle::ty::{self, AdtKind, Ty, TyCtxt};
+use rustc_middle::ty::{self, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt};
 use rustc_middle::{bug, span_bug};
 use rustc_span::hygiene::{AstPass, MacroKind};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::ExpnKind;
 use rustc_trait_selection::traits::wf::object_region_bounds;
-
-use std::borrow::Cow;
-use std::collections::BTreeMap;
-use std::mem;
 use thin_vec::ThinVec;
-
-use crate::core::DocContext;
-use crate::formats::item_type::ItemType;
-use crate::visit_ast::Module as DocModule;
-
 use utils::*;
+use {rustc_ast as ast, rustc_attr as attr, rustc_hir as hir};
 
 pub(crate) use self::types::*;
 pub(crate) use self::utils::{krate, register_res, synthesize_auto_trait_and_blanket_impls};
+use crate::core::DocContext;
+use crate::formats::item_type::ItemType;
+use crate::visit_ast::Module as DocModule;
 
 pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
     let mut items: Vec<Item> = vec![];
@@ -287,23 +282,21 @@ fn clean_lifetime<'tcx>(lifetime: &hir::Lifetime, cx: &mut DocContext<'tcx>) ->
 pub(crate) fn clean_const<'tcx>(
     constant: &hir::ConstArg<'tcx>,
     _cx: &mut DocContext<'tcx>,
-) -> Constant {
+) -> ConstantKind {
     match &constant.kind {
         hir::ConstArgKind::Path(qpath) => {
-            Constant { kind: ConstantKind::Path { path: qpath_to_string(&qpath).into() } }
-        }
-        hir::ConstArgKind::Anon(anon) => {
-            Constant { kind: ConstantKind::Anonymous { body: anon.body } }
+            ConstantKind::Path { path: qpath_to_string(&qpath).into() }
         }
+        hir::ConstArgKind::Anon(anon) => ConstantKind::Anonymous { body: anon.body },
     }
 }
 
 pub(crate) fn clean_middle_const<'tcx>(
     constant: ty::Binder<'tcx, ty::Const<'tcx>>,
     _cx: &mut DocContext<'tcx>,
-) -> Constant {
+) -> ConstantKind {
     // FIXME: instead of storing the stringified expression, store `self` directly instead.
-    Constant { kind: ConstantKind::TyConst { expr: constant.skip_binder().to_string().into() } }
+    ConstantKind::TyConst { expr: constant.skip_binder().to_string().into() }
 }
 
 pub(crate) fn clean_middle_region<'tcx>(region: ty::Region<'tcx>) -> Option<Lifetime> {
@@ -1230,14 +1223,11 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext
     let local_did = trait_item.owner_id.to_def_id();
     cx.with_param_env(local_did, |cx| {
         let inner = match trait_item.kind {
-            hir::TraitItemKind::Const(ty, Some(default)) => {
-                let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
-                AssocConstItem(
-                    generics,
-                    Box::new(clean_ty(ty, cx)),
-                    ConstantKind::Local { def_id: local_did, body: default },
-                )
-            }
+            hir::TraitItemKind::Const(ty, Some(default)) => AssocConstItem(Box::new(Constant {
+                generics: enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)),
+                kind: ConstantKind::Local { def_id: local_did, body: default },
+                type_: clean_ty(ty, cx),
+            })),
             hir::TraitItemKind::Const(ty, None) => {
                 let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
                 TyAssocConstItem(generics, Box::new(clean_ty(ty, cx)))
@@ -1282,11 +1272,11 @@ pub(crate) fn clean_impl_item<'tcx>(
     let local_did = impl_.owner_id.to_def_id();
     cx.with_param_env(local_did, |cx| {
         let inner = match impl_.kind {
-            hir::ImplItemKind::Const(ty, expr) => {
-                let generics = clean_generics(impl_.generics, cx);
-                let default = ConstantKind::Local { def_id: local_did, body: expr };
-                AssocConstItem(generics, Box::new(clean_ty(ty, cx)), default)
-            }
+            hir::ImplItemKind::Const(ty, expr) => AssocConstItem(Box::new(Constant {
+                generics: clean_generics(impl_.generics, cx),
+                kind: ConstantKind::Local { def_id: local_did, body: expr },
+                type_: clean_ty(ty, cx),
+            })),
             hir::ImplItemKind::Fn(ref sig, body) => {
                 let m = clean_function(cx, sig, impl_.generics, FunctionArgs::Body(body));
                 let defaultness = cx.tcx.defaultness(impl_.owner_id);
@@ -1320,12 +1310,12 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
     let tcx = cx.tcx;
     let kind = match assoc_item.kind {
         ty::AssocKind::Const => {
-            let ty = Box::new(clean_middle_ty(
+            let ty = clean_middle_ty(
                 ty::Binder::dummy(tcx.type_of(assoc_item.def_id).instantiate_identity()),
                 cx,
                 Some(assoc_item.def_id),
                 None,
-            ));
+            );
 
             let mut generics = clean_ty_generics(
                 cx,
@@ -1339,9 +1329,13 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
                 ty::TraitContainer => tcx.defaultness(assoc_item.def_id).has_value(),
             };
             if provided {
-                AssocConstItem(generics, ty, ConstantKind::Extern { def_id: assoc_item.def_id })
+                AssocConstItem(Box::new(Constant {
+                    generics,
+                    kind: ConstantKind::Extern { def_id: assoc_item.def_id },
+                    type_: ty,
+                }))
             } else {
-                TyAssocConstItem(generics, ty)
+                TyAssocConstItem(generics, Box::new(ty))
             }
         }
         ty::AssocKind::Fn => {
@@ -1357,11 +1351,11 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
                 let self_arg_ty =
                     tcx.fn_sig(assoc_item.def_id).instantiate_identity().input(0).skip_binder();
                 if self_arg_ty == self_ty {
-                    item.decl.inputs.values[0].type_ = Generic(kw::SelfUpper);
+                    item.decl.inputs.values[0].type_ = SelfTy;
                 } else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() {
                     if ty == self_ty {
                         match item.decl.inputs.values[0].type_ {
-                            BorrowedRef { ref mut type_, .. } => **type_ = Generic(kw::SelfUpper),
+                            BorrowedRef { ref mut type_, .. } => **type_ = SelfTy,
                             _ => unreachable!(),
                         }
                     }
@@ -1397,7 +1391,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
                     {
                         true
                     }
-                    (GenericParamDefKind::Const { .. }, GenericArg::Const(c)) => match &c.kind {
+                    (GenericParamDefKind::Const { .. }, GenericArg::Const(c)) => match &**c {
                         ConstantKind::TyConst { expr } => **expr == *param.name.as_str(),
                         _ => false,
                     },
@@ -1445,9 +1439,8 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
                         if trait_.def_id() != assoc_item.container_id(tcx) {
                             return true;
                         }
-                        match *self_type {
-                            Generic(ref s) if *s == kw::SelfUpper => {}
-                            _ => return true,
+                        if *self_type != SelfTy {
+                            return true;
                         }
                         match &assoc.args {
                             GenericArgs::AngleBracketed { args, constraints } => {
@@ -2234,6 +2227,8 @@ pub(crate) fn clean_middle_ty<'tcx>(
         ty::Param(ref p) => {
             if let Some(bounds) = cx.impl_trait_bounds.remove(&p.index.into()) {
                 ImplTrait(bounds)
+            } else if p.name == kw::SelfUpper {
+                SelfTy
             } else {
                 Generic(p.name)
             }
@@ -2744,18 +2739,19 @@ fn clean_maybe_renamed_item<'tcx>(
     let mut name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id()));
     cx.with_param_env(def_id, |cx| {
         let kind = match item.kind {
-            ItemKind::Static(ty, mutability, body_id) => {
-                StaticItem(Static { type_: clean_ty(ty, cx), mutability, expr: Some(body_id) })
-            }
-            ItemKind::Const(ty, generics, body_id) => ConstantItem(
-                clean_generics(generics, cx),
-                Box::new(clean_ty(ty, cx)),
-                Constant { kind: ConstantKind::Local { body: body_id, def_id } },
-            ),
-            ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy {
-                bounds: ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
-                generics: clean_generics(ty.generics, cx),
+            ItemKind::Static(ty, mutability, body_id) => StaticItem(Static {
+                type_: Box::new(clean_ty(ty, cx)),
+                mutability,
+                expr: Some(body_id),
             }),
+            ItemKind::Const(ty, generics, body_id) => ConstantItem(Box::new(Constant {
+                generics: clean_generics(generics, cx),
+                type_: clean_ty(ty, cx),
+                kind: ConstantKind::Local { body: body_id, def_id },
+            })),
+            // clean_ty changes types which reference an OpaqueTy item to instead be
+            // an ImplTrait, so it's ok to return nothing here.
+            ItemKind::OpaqueTy(_) => return vec![],
             ItemKind::TyAlias(hir_ty, generics) => {
                 *cx.current_type_aliases.entry(def_id).or_insert(0) += 1;
                 let rustdoc_ty = clean_ty(hir_ty, cx);
@@ -2838,7 +2834,7 @@ fn clean_maybe_renamed_item<'tcx>(
             ItemKind::Use(path, kind) => {
                 return clean_use_statement(item, name, path, kind, cx, &mut FxHashSet::default());
             }
-            _ => unreachable!("not yet converted"),
+            _ => span_bug!(item.span, "not yet converted"),
         };
 
         vec![generate_item_with_correct_attrs(
@@ -3109,7 +3105,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>(
                 ForeignFunctionItem(Box::new(Function { decl, generics }), safety)
             }
             hir::ForeignItemKind::Static(ty, mutability, safety) => ForeignStaticItem(
-                Static { type_: clean_ty(ty, cx), mutability, expr: None },
+                Static { type_: Box::new(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 1b7d84add1f..1d81ae3eb8b 100644
--- a/src/librustdoc/clean/simplify.rs
+++ b/src/librustdoc/clean/simplify.rs
@@ -18,8 +18,7 @@ use rustc_middle::ty;
 use thin_vec::ThinVec;
 
 use crate::clean;
-use crate::clean::GenericArgs as PP;
-use crate::clean::WherePredicate as WP;
+use crate::clean::{GenericArgs as PP, WherePredicate as WP};
 use crate::core::DocContext;
 
 pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: ThinVec<WP>) -> ThinVec<WP> {
@@ -146,7 +145,6 @@ pub(crate) fn sized_bounds(cx: &mut DocContext<'_>, generics: &mut clean::Generi
     // should be handled when cleaning associated types.
     generics.where_predicates.retain(|pred| {
         if let WP::BoundPredicate { ty: clean::Generic(param), bounds, .. } = pred
-            && *param != rustc_span::symbol::kw::SelfUpper
             && bounds.iter().any(|b| b.is_sized_bound(cx))
         {
             sized_params.insert(*param);
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 37099531596..ff5c16f2b3e 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -3,19 +3,14 @@ use std::cell::RefCell;
 use std::hash::Hash;
 use std::path::PathBuf;
 use std::rc::Rc;
-use std::sync::Arc;
-use std::sync::OnceLock as OnceCell;
+use std::sync::{Arc, OnceLock as OnceCell};
 use std::{fmt, iter};
 
 use arrayvec::ArrayVec;
-use thin_vec::ThinVec;
-
-use rustc_ast as ast;
 use rustc_ast_pretty::pprust;
 use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel, StableSince};
 use rustc_const_eval::const_eval::is_unstable_const_fn;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc_hir::lang_items::LangItem;
@@ -35,7 +30,14 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{FileName, Loc, DUMMY_SP};
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::abi::Abi;
+use thin_vec::ThinVec;
+use {rustc_ast as ast, rustc_hir as hir};
 
+pub(crate) use self::ItemKind::*;
+pub(crate) use self::Type::{
+    Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, QPath,
+    RawPointer, SelfTy, Slice, Tuple,
+};
 use crate::clean::cfg::Cfg;
 use crate::clean::clean_middle_path;
 use crate::clean::inline::{self, print_inlined_const};
@@ -46,13 +48,6 @@ use crate::formats::item_type::ItemType;
 use crate::html::render::Context;
 use crate::passes::collect_intra_doc_links::UrlFragment;
 
-pub(crate) use self::ItemKind::*;
-pub(crate) use self::SelfTy::*;
-pub(crate) use self::Type::{
-    Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, QPath,
-    RawPointer, Slice, Tuple,
-};
-
 #[cfg(test)]
 mod tests;
 
@@ -828,7 +823,6 @@ pub(crate) enum ItemKind {
     FunctionItem(Box<Function>),
     ModuleItem(Module),
     TypeAliasItem(Box<TypeAlias>),
-    OpaqueTyItem(OpaqueTy),
     StaticItem(Static),
     TraitItem(Box<Trait>),
     TraitAliasItem(TraitAlias),
@@ -852,9 +846,9 @@ pub(crate) enum ItemKind {
     PrimitiveItem(PrimitiveType),
     /// A required associated constant in a trait declaration.
     TyAssocConstItem(Generics, Box<Type>),
-    ConstantItem(Generics, Box<Type>, Constant),
+    ConstantItem(Box<Constant>),
     /// An associated constant in a trait impl or a provided one in a trait declaration.
-    AssocConstItem(Generics, Box<Type>, ConstantKind),
+    AssocConstItem(Box<Constant>),
     /// A required associated type in a trait declaration.
     ///
     /// The bounds may be non-empty if there is a `where` clause.
@@ -886,9 +880,8 @@ impl ItemKind {
             | ImportItem(_)
             | FunctionItem(_)
             | TypeAliasItem(_)
-            | OpaqueTyItem(_)
             | StaticItem(_)
-            | ConstantItem(_, _, _)
+            | ConstantItem(_)
             | TraitAliasItem(_)
             | TyMethodItem(_)
             | MethodItem(_, _)
@@ -920,9 +913,8 @@ impl ItemKind {
                 | ExternCrateItem { .. }
                 | FunctionItem(_)
                 | TypeAliasItem(_)
-                | OpaqueTyItem(_)
                 | StaticItem(_)
-                | ConstantItem(_, _, _)
+                | ConstantItem(_)
                 | TraitAliasItem(_)
                 | ForeignFunctionItem(_, _)
                 | ForeignStaticItem(_, _)
@@ -1391,8 +1383,8 @@ pub(crate) struct FnDecl {
 }
 
 impl FnDecl {
-    pub(crate) fn self_type(&self) -> Option<SelfTy> {
-        self.inputs.values.get(0).and_then(|v| v.to_self())
+    pub(crate) fn receiver_type(&self) -> Option<&Type> {
+        self.inputs.values.get(0).and_then(|v| v.to_receiver())
     }
 }
 
@@ -1410,27 +1402,9 @@ pub(crate) struct Argument {
     pub(crate) is_const: bool,
 }
 
-#[derive(Clone, PartialEq, Debug)]
-pub(crate) enum SelfTy {
-    SelfValue,
-    SelfBorrowed(Option<Lifetime>, Mutability),
-    SelfExplicit(Type),
-}
-
 impl Argument {
-    pub(crate) fn to_self(&self) -> Option<SelfTy> {
-        if self.name != kw::SelfLower {
-            return None;
-        }
-        if self.type_.is_self_type() {
-            return Some(SelfValue);
-        }
-        match self.type_ {
-            BorrowedRef { ref lifetime, mutability, ref type_ } if type_.is_self_type() => {
-                Some(SelfBorrowed(lifetime.clone(), mutability))
-            }
-            _ => Some(SelfExplicit(self.type_.clone())),
-        }
+    pub(crate) fn to_receiver(&self) -> Option<&Type> {
+        if self.name == kw::SelfLower { Some(&self.type_) } else { None }
     }
 }
 
@@ -1484,6 +1458,8 @@ pub(crate) enum Type {
     DynTrait(Vec<PolyTrait>, Option<Lifetime>),
     /// A type parameter.
     Generic(Symbol),
+    /// The `Self` type.
+    SelfTy,
     /// A primitive (aka, builtin) type.
     Primitive(PrimitiveType),
     /// A function pointer: `extern "ABI" fn(...) -> ...`
@@ -1578,6 +1554,8 @@ impl Type {
             // If both sides are generic, this returns true.
             (_, Type::Generic(_)) => true,
             (Type::Generic(_), _) => false,
+            // `Self` only matches itself.
+            (Type::SelfTy, Type::SelfTy) => true,
             // Paths account for both the path itself and its generics.
             (Type::Path { path: a }, Type::Path { path: b }) => {
                 a.def_id() == b.def_id()
@@ -1649,7 +1627,7 @@ impl Type {
 
     pub(crate) fn is_self_type(&self) -> bool {
         match *self {
-            Generic(name) => name == kw::SelfUpper,
+            SelfTy => true,
             _ => false,
         }
     }
@@ -1684,13 +1662,16 @@ impl Type {
         }
     }
 
-    fn inner_def_id(&self, cache: Option<&Cache>) -> Option<DefId> {
+    /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s.
+    ///
+    /// [clean]: crate::clean
+    pub(crate) fn def_id(&self, cache: &Cache) -> Option<DefId> {
         let t: PrimitiveType = match *self {
             Type::Path { ref path } => return Some(path.def_id()),
             DynTrait(ref bounds, _) => return bounds.get(0).map(|b| b.trait_.def_id()),
-            Primitive(p) => return cache.and_then(|c| c.primitive_locations.get(&p).cloned()),
+            Primitive(p) => return cache.primitive_locations.get(&p).cloned(),
             BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
-            BorrowedRef { ref type_, .. } => return type_.inner_def_id(cache),
+            BorrowedRef { ref type_, .. } => return type_.def_id(cache),
             Tuple(ref tys) => {
                 if tys.is_empty() {
                     PrimitiveType::Unit
@@ -1703,17 +1684,10 @@ impl Type {
             Array(..) => PrimitiveType::Array,
             Type::Pat(..) => PrimitiveType::Pat,
             RawPointer(..) => PrimitiveType::RawPointer,
-            QPath(box QPathData { ref self_type, .. }) => return self_type.inner_def_id(cache),
-            Generic(_) | Infer | ImplTrait(_) => return None,
+            QPath(box QPathData { ref self_type, .. }) => return self_type.def_id(cache),
+            Generic(_) | SelfTy | Infer | ImplTrait(_) => return None,
         };
-        cache.and_then(|c| Primitive(t).def_id(c))
-    }
-
-    /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s.
-    ///
-    /// [clean]: crate::clean
-    pub(crate) fn def_id(&self, cache: &Cache) -> Option<DefId> {
-        self.inner_def_id(Some(cache))
+        Primitive(t).def_id(cache)
     }
 }
 
@@ -2050,7 +2024,7 @@ impl From<hir::PrimTy> for PrimitiveType {
 pub(crate) struct Struct {
     pub(crate) ctor_kind: Option<CtorKind>,
     pub(crate) generics: Generics,
-    pub(crate) fields: Vec<Item>,
+    pub(crate) fields: ThinVec<Item>,
 }
 
 impl Struct {
@@ -2076,7 +2050,7 @@ impl Union {
 /// only as a variant in an enum.
 #[derive(Clone, Debug)]
 pub(crate) struct VariantStruct {
-    pub(crate) fields: Vec<Item>,
+    pub(crate) fields: ThinVec<Item>,
 }
 
 impl VariantStruct {
@@ -2110,7 +2084,7 @@ pub(crate) struct Variant {
 #[derive(Clone, Debug)]
 pub(crate) enum VariantKind {
     CLike,
-    Tuple(Vec<Item>),
+    Tuple(ThinVec<Item>),
     Struct(VariantStruct),
 }
 
@@ -2246,7 +2220,7 @@ impl Path {
 pub(crate) enum GenericArg {
     Lifetime(Lifetime),
     Type(Type),
-    Const(Box<Constant>),
+    Const(Box<ConstantKind>),
     Infer,
 }
 
@@ -2343,12 +2317,6 @@ pub(crate) struct TypeAlias {
     pub(crate) item_type: Option<Type>,
 }
 
-#[derive(Clone, Debug)]
-pub(crate) struct OpaqueTy {
-    pub(crate) bounds: Vec<GenericBound>,
-    pub(crate) generics: Generics,
-}
-
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub(crate) struct BareFunctionDecl {
     pub(crate) safety: hir::Safety,
@@ -2359,20 +2327,22 @@ pub(crate) struct BareFunctionDecl {
 
 #[derive(Clone, Debug)]
 pub(crate) struct Static {
-    pub(crate) type_: Type,
+    pub(crate) type_: Box<Type>,
     pub(crate) mutability: Mutability,
     pub(crate) expr: Option<BodyId>,
 }
 
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
 pub(crate) struct Constant {
+    pub(crate) generics: Generics,
     pub(crate) kind: ConstantKind,
+    pub(crate) type_: Type,
 }
 
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
 pub(crate) enum Term {
     Type(Type),
-    Constant(Constant),
+    Constant(ConstantKind),
 }
 
 impl Term {
@@ -2476,6 +2446,10 @@ impl Impl {
             .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name).collect())
             .unwrap_or_default()
     }
+
+    pub(crate) fn is_negative_trait_impl(&self) -> bool {
+        matches!(self.polarity, ty::ImplPolarity::Negative)
+    }
 }
 
 #[derive(Clone, Debug)]
@@ -2584,8 +2558,9 @@ pub(crate) enum AssocItemConstraintKind {
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
 #[cfg(target_pointer_width = "64")]
 mod size_asserts {
-    use super::*;
     use rustc_data_structures::static_assert_size;
+
+    use super::*;
     // tidy-alphabetical-start
     static_assert_size!(Crate, 64); // frequently moved by-value
     static_assert_size!(DocFragment, 32);
@@ -2594,7 +2569,7 @@ mod size_asserts {
     static_assert_size!(GenericParamDef, 40);
     static_assert_size!(Generics, 16);
     static_assert_size!(Item, 56);
-    static_assert_size!(ItemKind, 56);
+    static_assert_size!(ItemKind, 48);
     static_assert_size!(PathSegment, 40);
     static_assert_size!(Type, 32);
     // tidy-alphabetical-end
diff --git a/src/librustdoc/clean/types/tests.rs b/src/librustdoc/clean/types/tests.rs
index 4befce07170..ddf6a11ec4e 100644
--- a/src/librustdoc/clean/types/tests.rs
+++ b/src/librustdoc/clean/types/tests.rs
@@ -1,8 +1,8 @@
-use super::*;
-
 use rustc_resolve::rustdoc::{unindent_doc_fragments, DocFragmentKind};
 use rustc_span::create_default_session_globals_then;
 
+use super::*;
+
 fn create_doc_fragment(s: &str) -> Vec<DocFragment> {
     vec![DocFragment {
         span: DUMMY_SP,
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 7c83d438719..68266f3506a 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -1,3 +1,18 @@
+use std::assert_matches::debug_assert_matches;
+use std::fmt::Write as _;
+use std::mem;
+use std::sync::LazyLock as Lazy;
+
+use rustc_ast::tokenstream::TokenTree;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
+use rustc_metadata::rendered_const;
+use rustc_middle::mir;
+use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, TyCtxt, TypeVisitableExt};
+use rustc_span::symbol::{kw, sym, Symbol};
+use thin_vec::{thin_vec, ThinVec};
+use {rustc_ast as ast, rustc_hir as hir};
+
 use crate::clean::auto_trait::synthesize_auto_trait_impls;
 use crate::clean::blanket_impl::synthesize_blanket_impls;
 use crate::clean::render_macro_matchers::render_macro_matcher;
@@ -10,22 +25,6 @@ use crate::clean::{
 use crate::core::DocContext;
 use crate::html::format::visibility_to_src_with_space;
 
-use rustc_ast as ast;
-use rustc_ast::tokenstream::TokenTree;
-use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
-use rustc_metadata::rendered_const;
-use rustc_middle::mir;
-use rustc_middle::ty::TypeVisitableExt;
-use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, TyCtxt};
-use rustc_span::symbol::{kw, sym, Symbol};
-use std::assert_matches::debug_assert_matches;
-use std::fmt::Write as _;
-use std::mem;
-use std::sync::LazyLock as Lazy;
-use thin_vec::{thin_vec, ThinVec};
-
 #[cfg(test)]
 mod tests;
 
@@ -469,7 +468,7 @@ pub(crate) fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type {
     match path.res {
         Res::PrimTy(p) => Primitive(PrimitiveType::from(p)),
         Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } if path.segments.len() == 1 => {
-            Generic(kw::SelfUpper)
+            Type::SelfTy
         }
         Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => Generic(path.segments[0].name),
         _ => {
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index 45bd1616e83..9c7a9f8467f 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -1,38 +1,32 @@
 use std::collections::BTreeMap;
 use std::ffi::OsStr;
-use std::fmt;
-use std::io;
 use std::io::Read;
-use std::path::Path;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
 use std::str::FromStr;
+use std::{fmt, io};
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::DiagCtxtHandle;
 use rustc_session::config::{
-    self, parse_crate_types_from_list, parse_externs, parse_target_triple, CrateType,
+    self, get_cmd_lint_options, nightly_options, parse_crate_types_from_list, parse_externs,
+    parse_target_triple, CodegenOptions, CrateType, ErrorOutputType, Externs, Input,
+    JsonUnusedExterns, UnstableOptions,
 };
-use rustc_session::config::{get_cmd_lint_options, nightly_options};
-use rustc_session::config::{CodegenOptions, ErrorOutputType, Externs, Input};
-use rustc_session::config::{JsonUnusedExterns, UnstableOptions};
-use rustc_session::getopts;
 use rustc_session::lint::Level;
 use rustc_session::search_paths::SearchPath;
-use rustc_session::EarlyDiagCtxt;
+use rustc_session::{getopts, EarlyDiagCtxt};
 use rustc_span::edition::Edition;
 use rustc_span::FileName;
 use rustc_target::spec::TargetTriple;
 
 use crate::core::new_dcx;
 use crate::externalfiles::ExternalHtml;
-use crate::html;
 use crate::html::markdown::IdMap;
 use crate::html::render::StylePath;
 use crate::html::static_files;
-use crate::opts;
 use crate::passes::{self, Condition};
 use crate::scrape_examples::{AllCallLocations, ScrapeExamplesOptions};
-use crate::theme;
+use crate::{html, opts, theme};
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
 pub(crate) enum OutputFormat {
@@ -368,9 +362,10 @@ impl Options {
         }
 
         let color = config::parse_color(early_dcx, matches);
-        let config::JsonConfig { json_rendered, json_unused_externs, .. } =
+        let config::JsonConfig { json_rendered, json_unused_externs, json_color, .. } =
             config::parse_json(early_dcx, matches);
-        let error_format = config::parse_error_format(early_dcx, matches, color, json_rendered);
+        let error_format =
+            config::parse_error_format(early_dcx, matches, color, json_color, json_rendered);
         let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_default();
 
         let codegen_options = CodegenOptions::build(early_dcx, matches);
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 5d8e61f9fa0..08a4a3f3fb2 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -1,9 +1,16 @@
+use std::cell::RefCell;
+use std::rc::Rc;
+use std::sync::atomic::AtomicBool;
+use std::sync::{Arc, LazyLock};
+use std::{io, mem};
+
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::unord::UnordSet;
+use rustc_errors::codes::*;
 use rustc_errors::emitter::{stderr_destination, DynEmitter, HumanEmitter};
 use rustc_errors::json::JsonEmitter;
-use rustc_errors::{codes::*, DiagCtxtHandle, ErrorGuaranteed, TerminalUrl};
+use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, TerminalUrl};
 use rustc_feature::UnstableFeatures;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId};
@@ -14,25 +21,17 @@ use rustc_lint::{late_lint_mod, MissingDoc};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
 use rustc_session::config::{self, CrateType, ErrorOutputType, ResolveDocLinks};
-use rustc_session::lint;
-use rustc_session::Session;
+pub(crate) use rustc_session::config::{Options, UnstableOptions};
+use rustc_session::{lint, Session};
 use rustc_span::symbol::sym;
 use rustc_span::{source_map, Span};
 
-use std::cell::RefCell;
-use std::io;
-use std::mem;
-use std::rc::Rc;
-use std::sync::LazyLock;
-use std::sync::{atomic::AtomicBool, Arc};
-
 use crate::clean::inline::build_external_trait;
 use crate::clean::{self, ItemId};
 use crate::config::{Options as RustdocOptions, OutputFormat, RenderOptions};
 use crate::formats::cache::Cache;
-use crate::passes::{self, Condition::*};
-
-pub(crate) use rustc_session::config::{Options, UnstableOptions};
+use crate::passes::Condition::*;
+use crate::passes::{self};
 
 pub(crate) struct DocContext<'tcx> {
     pub(crate) tcx: TyCtxt<'tcx>,
@@ -139,8 +138,8 @@ pub(crate) fn new_dcx(
         false,
     );
     let emitter: Box<DynEmitter> = match error_format {
-        ErrorOutputType::HumanReadable(kind) => {
-            let (short, color_config) = kind.unzip();
+        ErrorOutputType::HumanReadable(kind, color_config) => {
+            let short = kind.short();
             Box::new(
                 HumanEmitter::new(stderr_destination(color_config), fallback_bundle)
                     .sm(source_map.map(|sm| sm as _))
@@ -151,7 +150,7 @@ pub(crate) fn new_dcx(
                     .ui_testing(unstable_opts.ui_testing),
             )
         }
-        ErrorOutputType::Json { pretty, json_rendered } => {
+        ErrorOutputType::Json { pretty, json_rendered, color_config } => {
             let source_map = source_map.unwrap_or_else(|| {
                 Lrc::new(source_map::SourceMap::new(source_map::FilePathMapping::empty()))
             });
@@ -162,6 +161,7 @@ pub(crate) fn new_dcx(
                     fallback_bundle,
                     pretty,
                     json_rendered,
+                    color_config,
                 )
                 .ui_testing(unstable_opts.ui_testing)
                 .diagnostic_width(diagnostic_width)
@@ -196,6 +196,7 @@ pub(crate) fn create_config(
         lint_cap,
         scrape_examples_options,
         expanded_args,
+        remap_path_prefix,
         ..
     }: RustdocOptions,
     RenderOptions { document_private, .. }: &RenderOptions,
@@ -248,6 +249,7 @@ pub(crate) fn create_config(
         describe_lints,
         crate_name,
         test,
+        remap_path_prefix,
         ..Options::default()
     };
 
diff --git a/src/librustdoc/docfs.rs b/src/librustdoc/docfs.rs
index 1f7abdfc315..0ca070ddb8e 100644
--- a/src/librustdoc/docfs.rs
+++ b/src/librustdoc/docfs.rs
@@ -9,11 +9,11 @@
 //! abstraction.
 
 use std::cmp::max;
-use std::fs;
-use std::io;
 use std::path::{Path, PathBuf};
 use std::sync::mpsc::Sender;
 use std::thread::available_parallelism;
+use std::{fs, io};
+
 use threadpool::ThreadPool;
 
 pub(crate) trait PathError {
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 40cc4a9d441..08d6a5a52b2 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -2,9 +2,16 @@ mod make;
 mod markdown;
 mod rust;
 
+use std::fs::File;
+use std::io::{self, Write};
+use std::path::{Path, PathBuf};
+use std::process::{self, Command, Stdio};
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::{Arc, Mutex};
+use std::{panic, str};
+
 pub(crate) use make::make_test;
 pub(crate) use markdown::test as test_markdown;
-
 use rustc_ast as ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{ColorConfig, DiagCtxtHandle, ErrorGuaranteed, FatalError};
@@ -17,24 +24,13 @@ use rustc_span::edition::Edition;
 use rustc_span::symbol::sym;
 use rustc_span::FileName;
 use rustc_target::spec::{Target, TargetTriple};
-
-use std::fs::File;
-use std::io::{self, Write};
-use std::panic;
-use std::path::{Path, PathBuf};
-use std::process::{self, Command, Stdio};
-use std::str;
-use std::sync::atomic::{AtomicUsize, Ordering};
-use std::sync::{Arc, Mutex};
-
 use tempfile::{Builder as TempFileBuilder, TempDir};
 
+use self::rust::HirCollector;
 use crate::config::Options as RustdocOptions;
 use crate::html::markdown::{ErrorCodes, Ignore, LangString, MdRelLine};
 use crate::lint::init_lints;
 
-use self::rust::HirCollector;
-
 /// Options that apply to all doctests in a crate or Markdown file (for `rustdoc foo.md`).
 #[derive(Clone)]
 pub(crate) struct GlobalTestOptions {
@@ -426,8 +422,8 @@ fn run_test(
             path_for_rustdoc.to_str().expect("target path must be valid unicode")
         }
     });
-    if let ErrorOutputType::HumanReadable(kind) = rustdoc_options.error_format {
-        let (short, color_config) = kind.unzip();
+    if let ErrorOutputType::HumanReadable(kind, color_config) = rustdoc_options.error_format {
+        let short = kind.short();
 
         if short {
             compiler.arg("--error-format").arg("short");
diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs
index fc8e119ccc2..f179f3aa1c9 100644
--- a/src/librustdoc/doctest/rust.rs
+++ b/src/librustdoc/doctest/rust.rs
@@ -2,7 +2,8 @@
 
 use std::env;
 
-use rustc_data_structures::{fx::FxHashSet, sync::Lrc};
+use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::sync::Lrc;
 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
 use rustc_hir::{self as hir, intravisit, CRATE_HIR_ID};
 use rustc_middle::hir::map::Map;
@@ -14,7 +15,8 @@ use rustc_span::source_map::SourceMap;
 use rustc_span::{BytePos, FileName, Pos, Span, DUMMY_SP};
 
 use super::{DoctestVisitor, ScrapedDoctest};
-use crate::clean::{types::AttributesExt, Attributes};
+use crate::clean::types::AttributesExt;
+use crate::clean::Attributes;
 use crate::html::markdown::{self, ErrorCodes, LangString, MdRelLine};
 
 struct RustCollector {
diff --git a/src/librustdoc/doctest/tests.rs b/src/librustdoc/doctest/tests.rs
index 9124ec63267..0f13ee404c6 100644
--- a/src/librustdoc/doctest/tests.rs
+++ b/src/librustdoc/doctest/tests.rs
@@ -1,8 +1,9 @@
 use std::path::PathBuf;
 
-use super::{make_test, GlobalTestOptions};
 use rustc_span::edition::DEFAULT_EDITION;
 
+use super::{make_test, GlobalTestOptions};
+
 /// Default [`GlobalTestOptions`] for these unit tests.
 fn default_global_opts(crate_name: impl Into<String>) -> GlobalTestOptions {
     GlobalTestOptions {
diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs
index 62cdc0bd5a6..b81fc5a0a71 100644
--- a/src/librustdoc/externalfiles.rs
+++ b/src/librustdoc/externalfiles.rs
@@ -1,12 +1,12 @@
-use crate::html::markdown::{ErrorCodes, HeadingOffset, IdMap, Markdown, Playground};
-use rustc_errors::DiagCtxtHandle;
-use rustc_span::edition::Edition;
-use std::fs;
 use std::path::Path;
-use std::str;
+use std::{fs, str};
 
+use rustc_errors::DiagCtxtHandle;
+use rustc_span::edition::Edition;
 use serde::Serialize;
 
+use crate::html::markdown::{ErrorCodes, HeadingOffset, IdMap, Markdown, Playground};
+
 #[derive(Clone, Debug, Serialize)]
 pub(crate) struct ExternalHtml {
     /// Content that will be included inline in the `<head>` section of a
diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs
index 346e9a4e113..bf82c911f29 100644
--- a/src/librustdoc/fold.rs
+++ b/src/librustdoc/fold.rs
@@ -77,9 +77,8 @@ pub(crate) trait DocFolder: Sized {
             ExternCrateItem { src: _ }
             | ImportItem(_)
             | FunctionItem(_)
-            | OpaqueTyItem(_)
             | StaticItem(_)
-            | ConstantItem(_, _, _)
+            | ConstantItem(..)
             | TraitAliasItem(_)
             | TyMethodItem(_)
             | MethodItem(_, _)
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index a3b88a880f2..947bae99305 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -5,7 +5,8 @@ use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet};
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::Symbol;
 
-use crate::clean::{self, types::ExternalLocation, ExternalCrate, ItemId, PrimitiveType};
+use crate::clean::types::ExternalLocation;
+use crate::clean::{self, ExternalCrate, ItemId, PrimitiveType};
 use crate::core::DocContext;
 use crate::fold::DocFolder;
 use crate::formats::item_type::ItemType;
@@ -259,153 +260,21 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
         }
 
         // Index this method for searching later on.
-        if let Some(s) = item.name.or_else(|| {
-            if item.is_stripped() {
-                None
-            } else if let clean::ImportItem(ref i) = *item.kind
-                && let clean::ImportKind::Simple(s) = i.kind
-            {
-                Some(s)
-            } else {
-                None
-            }
-        }) {
-            let (parent, is_inherent_impl_item) = match *item.kind {
-                clean::StrippedItem(..) => ((None, None), false),
-                clean::AssocConstItem(..) | clean::AssocTypeItem(..)
-                    if self
-                        .cache
-                        .parent_stack
-                        .last()
-                        .is_some_and(|parent| parent.is_trait_impl()) =>
+        let search_name = if !item.is_stripped() {
+            item.name.or_else(|| {
+                if let clean::ImportItem(ref i) = *item.kind
+                    && let clean::ImportKind::Simple(s) = i.kind
                 {
-                    // skip associated items in trait impls
-                    ((None, None), false)
-                }
-                clean::TyMethodItem(..)
-                | clean::TyAssocConstItem(..)
-                | clean::TyAssocTypeItem(..)
-                | clean::StructFieldItem(..)
-                | clean::VariantItem(..) => (
-                    (
-                        Some(
-                            self.cache
-                                .parent_stack
-                                .last()
-                                .expect("parent_stack is empty")
-                                .item_id()
-                                .expect_def_id(),
-                        ),
-                        Some(&self.cache.stack[..self.cache.stack.len() - 1]),
-                    ),
-                    false,
-                ),
-                clean::MethodItem(..) | clean::AssocConstItem(..) | clean::AssocTypeItem(..) => {
-                    if self.cache.parent_stack.is_empty() {
-                        ((None, None), false)
-                    } else {
-                        let last = self.cache.parent_stack.last().expect("parent_stack is empty 2");
-                        let did = match &*last {
-                            ParentStackItem::Impl {
-                                // impl Trait for &T { fn method(self); }
-                                //
-                                // When generating a function index with the above shape, we want it
-                                // associated with `T`, not with the primitive reference type. It should
-                                // show up as `T::method`, rather than `reference::method`, in the search
-                                // results page.
-                                for_: clean::Type::BorrowedRef { type_, .. },
-                                ..
-                            } => type_.def_id(&self.cache),
-                            ParentStackItem::Impl { for_, .. } => for_.def_id(&self.cache),
-                            ParentStackItem::Type(item_id) => item_id.as_def_id(),
-                        };
-                        let path = did
-                            .and_then(|did| self.cache.paths.get(&did))
-                            // The current stack not necessarily has correlation
-                            // for where the type was defined. On the other
-                            // hand, `paths` always has the right
-                            // information if present.
-                            .map(|(fqp, _)| &fqp[..fqp.len() - 1]);
-                        ((did, path), true)
-                    }
-                }
-                _ => ((None, Some(&*self.cache.stack)), false),
-            };
-
-            match parent {
-                (parent, Some(path)) if is_inherent_impl_item || !self.cache.stripped_mod => {
-                    debug_assert!(!item.is_stripped());
-
-                    // A crate has a module at its root, containing all items,
-                    // which should not be indexed. The crate-item itself is
-                    // inserted later on when serializing the search-index.
-                    if item.item_id.as_def_id().is_some_and(|idx| !idx.is_crate_root())
-                        && let ty = item.type_()
-                        && (ty != ItemType::StructField
-                            || u16::from_str_radix(s.as_str(), 10).is_err())
-                    {
-                        let desc =
-                            short_markdown_summary(&item.doc_value(), &item.link_names(self.cache));
-                        // For searching purposes, a re-export is a duplicate if:
-                        //
-                        // - It's either an inline, or a true re-export
-                        // - It's got the same name
-                        // - Both of them have the same exact path
-                        let defid = (match &*item.kind {
-                            &clean::ItemKind::ImportItem(ref import) => import.source.did,
-                            _ => None,
-                        })
-                        .or_else(|| item.item_id.as_def_id());
-                        // In case this is a field from a tuple struct, we don't add it into
-                        // the search index because its name is something like "0", which is
-                        // not useful for rustdoc search.
-                        self.cache.search_index.push(IndexItem {
-                            ty,
-                            defid,
-                            name: s,
-                            path: join_with_double_colon(path),
-                            desc,
-                            parent,
-                            parent_idx: None,
-                            exact_path: None,
-                            impl_id: if let Some(ParentStackItem::Impl { item_id, .. }) =
-                                self.cache.parent_stack.last()
-                            {
-                                item_id.as_def_id()
-                            } else {
-                                None
-                            },
-                            search_type: get_function_type_for_search(
-                                &item,
-                                self.tcx,
-                                clean_impl_generics(self.cache.parent_stack.last()).as_ref(),
-                                parent,
-                                self.cache,
-                            ),
-                            aliases: item.attrs.get_doc_aliases(),
-                            deprecation: item.deprecation(self.tcx),
-                        });
-                    }
+                    Some(s)
+                } else {
+                    None
                 }
-                (Some(parent), None) if is_inherent_impl_item => {
-                    // We have a parent, but we don't know where they're
-                    // defined yet. Wait for later to index this item.
-                    let impl_generics = clean_impl_generics(self.cache.parent_stack.last());
-                    self.cache.orphan_impl_items.push(OrphanImplItem {
-                        parent,
-                        item: item.clone(),
-                        impl_generics,
-                        impl_id: if let Some(ParentStackItem::Impl { item_id, .. }) =
-                            self.cache.parent_stack.last()
-                        {
-                            item_id.as_def_id()
-                        } else {
-                            None
-                        },
-                    });
-                }
-                _ => {}
-            }
+            })
+        } else {
+            None
+        };
+        if let Some(name) = search_name {
+            add_item_to_search_index(self.tcx, &mut self.cache, &item, name)
         }
 
         // Keep track of the fully qualified path for this item.
@@ -441,16 +310,16 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
                     // `public_items` map, so we can skip inserting into the
                     // paths map if there was already an entry present and we're
                     // not a public item.
-                    if !self.cache.paths.contains_key(&item.item_id.expect_def_id())
+                    let item_def_id = item.item_id.expect_def_id();
+                    if !self.cache.paths.contains_key(&item_def_id)
                         || self
                             .cache
                             .effective_visibilities
-                            .is_directly_public(self.tcx, item.item_id.expect_def_id())
+                            .is_directly_public(self.tcx, item_def_id)
                     {
-                        self.cache.paths.insert(
-                            item.item_id.expect_def_id(),
-                            (self.cache.stack.clone(), item.type_()),
-                        );
+                        self.cache
+                            .paths
+                            .insert(item_def_id, (self.cache.stack.clone(), item.type_()));
                     }
                 }
             }
@@ -462,7 +331,6 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
 
             clean::ExternCrateItem { .. }
             | clean::ImportItem(..)
-            | clean::OpaqueTyItem(..)
             | clean::ImplItem(..)
             | clean::TyMethodItem(..)
             | clean::MethodItem(..)
@@ -513,9 +381,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
                         && adt.is_fundamental()
                     {
                         for ty in generics {
-                            if let Some(did) = ty.def_id(self.cache) {
-                                dids.insert(did);
-                            }
+                            dids.extend(ty.def_id(self.cache));
                         }
                     }
                 }
@@ -528,32 +394,26 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
                         .primitive_type()
                         .and_then(|t| self.cache.primitive_locations.get(&t).cloned());
 
-                    if let Some(did) = did {
-                        dids.insert(did);
-                    }
+                    dids.extend(did);
                 }
             }
 
             if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) {
                 for bound in generics {
-                    if let Some(did) = bound.def_id(self.cache) {
-                        dids.insert(did);
-                    }
+                    dids.extend(bound.def_id(self.cache));
                 }
             }
             let impl_item = Impl { impl_item: item };
-            if impl_item.trait_did().map_or(true, |d| self.cache.traits.contains_key(&d)) {
+            let impl_did = impl_item.def_id();
+            let trait_did = impl_item.trait_did();
+            if trait_did.map_or(true, |d| self.cache.traits.contains_key(&d)) {
                 for did in dids {
-                    if self.impl_ids.entry(did).or_default().insert(impl_item.def_id()) {
-                        self.cache
-                            .impls
-                            .entry(did)
-                            .or_insert_with(Vec::new)
-                            .push(impl_item.clone());
+                    if self.impl_ids.entry(did).or_default().insert(impl_did) {
+                        self.cache.impls.entry(did).or_default().push(impl_item.clone());
                     }
                 }
             } else {
-                let trait_did = impl_item.trait_did().expect("no trait did");
+                let trait_did = trait_did.expect("no trait did");
                 self.cache.orphan_trait_impls.push((trait_did, dids, impl_item));
             }
             None
@@ -572,6 +432,152 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
     }
 }
 
+fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::Item, name: Symbol) {
+    // Item has a name, so it must also have a DefId (can't be an impl, let alone a blanket or auto impl).
+    let item_def_id = item.item_id.as_def_id().unwrap();
+    let (parent_did, parent_path) = match *item.kind {
+        clean::StrippedItem(..) => return,
+        clean::AssocConstItem(..) | clean::AssocTypeItem(..)
+            if cache.parent_stack.last().is_some_and(|parent| parent.is_trait_impl()) =>
+        {
+            // skip associated items in trait impls
+            return;
+        }
+        clean::TyMethodItem(..)
+        | clean::TyAssocConstItem(..)
+        | clean::TyAssocTypeItem(..)
+        | clean::StructFieldItem(..)
+        | clean::VariantItem(..) => {
+            // Don't index if containing module is stripped (i.e., private),
+            // or if item is tuple struct/variant field (name is a number -> not useful for search).
+            if cache.stripped_mod
+                || item.type_() == ItemType::StructField
+                    && name.as_str().chars().all(|c| c.is_digit(10))
+            {
+                return;
+            }
+            let parent_did =
+                cache.parent_stack.last().expect("parent_stack is empty").item_id().expect_def_id();
+            let parent_path = &cache.stack[..cache.stack.len() - 1];
+            (Some(parent_did), parent_path)
+        }
+        clean::MethodItem(..) | clean::AssocConstItem(..) | clean::AssocTypeItem(..) => {
+            let last = cache.parent_stack.last().expect("parent_stack is empty 2");
+            let parent_did = match &*last {
+                // impl Trait for &T { fn method(self); }
+                //
+                // When generating a function index with the above shape, we want it
+                // associated with `T`, not with the primitive reference type. It should
+                // show up as `T::method`, rather than `reference::method`, in the search
+                // results page.
+                ParentStackItem::Impl { for_: clean::Type::BorrowedRef { type_, .. }, .. } => {
+                    type_.def_id(&cache)
+                }
+                ParentStackItem::Impl { for_, .. } => for_.def_id(&cache),
+                ParentStackItem::Type(item_id) => item_id.as_def_id(),
+            };
+            let Some(parent_did) = parent_did else { return };
+            // The current stack reflects the CacheBuilder's recursive
+            // walk over HIR. For associated items, this is the module
+            // where the `impl` block is defined. That's an implementation
+            // detail that we don't want to affect the search engine.
+            //
+            // In particular, you can arrange things like this:
+            //
+            //     #![crate_name="me"]
+            //     mod private_mod {
+            //         impl Clone for MyThing { fn clone(&self) -> MyThing { MyThing } }
+            //     }
+            //     pub struct MyThing;
+            //
+            // When that happens, we need to:
+            // - ignore the `cache.stripped_mod` flag, since the Clone impl is actually
+            //   part of the public API even though it's defined in a private module
+            // - present the method as `me::MyThing::clone`, its publicly-visible path
+            // - deal with the fact that the recursive walk hasn't actually reached `MyThing`
+            //   until it's already past `private_mod`, since that's first, and doesn't know
+            //   yet if `MyThing` will actually be public or not (it could be re-exported)
+            //
+            // We accomplish the last two points by recording children of "orphan impls"
+            // in a field of the cache whose elements are added to the search index later,
+            // after cache building is complete (see `handle_orphan_impl_child`).
+            match cache.paths.get(&parent_did) {
+                Some((fqp, _)) => (Some(parent_did), &fqp[..fqp.len() - 1]),
+                None => {
+                    handle_orphan_impl_child(cache, item, parent_did);
+                    return;
+                }
+            }
+        }
+        _ => {
+            // Don't index if item is crate root, which is inserted later on when serializing the index.
+            // Don't index if containing module is stripped (i.e., private),
+            if item_def_id.is_crate_root() || cache.stripped_mod {
+                return;
+            }
+            (None, &*cache.stack)
+        }
+    };
+
+    debug_assert!(!item.is_stripped());
+
+    let desc = short_markdown_summary(&item.doc_value(), &item.link_names(cache));
+    // For searching purposes, a re-export is a duplicate if:
+    //
+    // - It's either an inline, or a true re-export
+    // - It's got the same name
+    // - Both of them have the same exact path
+    let defid = match &*item.kind {
+        clean::ItemKind::ImportItem(import) => import.source.did.unwrap_or(item_def_id),
+        _ => item_def_id,
+    };
+    let path = join_with_double_colon(parent_path);
+    let impl_id = if let Some(ParentStackItem::Impl { item_id, .. }) = cache.parent_stack.last() {
+        item_id.as_def_id()
+    } else {
+        None
+    };
+    let search_type = get_function_type_for_search(
+        &item,
+        tcx,
+        clean_impl_generics(cache.parent_stack.last()).as_ref(),
+        parent_did,
+        cache,
+    );
+    let aliases = item.attrs.get_doc_aliases();
+    let deprecation = item.deprecation(tcx);
+    let index_item = IndexItem {
+        ty: item.type_(),
+        defid: Some(defid),
+        name,
+        path,
+        desc,
+        parent: parent_did,
+        parent_idx: None,
+        exact_path: None,
+        impl_id,
+        search_type,
+        aliases,
+        deprecation,
+    };
+    cache.search_index.push(index_item);
+}
+
+/// We have a parent, but we don't know where they're
+/// defined yet. Wait for later to index this item.
+/// See [`Cache::orphan_impl_items`].
+fn handle_orphan_impl_child(cache: &mut Cache, item: &clean::Item, parent_did: DefId) {
+    let impl_generics = clean_impl_generics(cache.parent_stack.last());
+    let impl_id = if let Some(ParentStackItem::Impl { item_id, .. }) = cache.parent_stack.last() {
+        item_id.as_def_id()
+    } else {
+        None
+    };
+    let orphan_item =
+        OrphanImplItem { parent: parent_did, item: item.clone(), impl_generics, impl_id };
+    cache.orphan_impl_items.push(orphan_item);
+}
+
 pub(crate) struct OrphanImplItem {
     pub(crate) parent: DefId,
     pub(crate) impl_id: Option<DefId>,
diff --git a/src/librustdoc/formats/item_type.rs b/src/librustdoc/formats/item_type.rs
index d5468798bd3..3dcef15b552 100644
--- a/src/librustdoc/formats/item_type.rs
+++ b/src/librustdoc/formats/item_type.rs
@@ -2,10 +2,9 @@
 
 use std::fmt;
 
-use serde::{Serialize, Serializer};
-
 use rustc_hir::def::{CtorOf, DefKind};
 use rustc_span::hygiene::MacroKind;
+use serde::{Serialize, Serializer};
 
 use crate::clean;
 
@@ -52,7 +51,7 @@ pub(crate) enum ItemType {
     AssocConst = 19,
     Union = 20,
     ForeignType = 21,
-    OpaqueTy = 22,
+    // OpaqueTy used to be here, but it was removed in #127276
     ProcAttribute = 23,
     ProcDerive = 24,
     TraitAlias = 25,
@@ -85,7 +84,6 @@ impl<'a> From<&'a clean::Item> for ItemType {
             clean::EnumItem(..) => ItemType::Enum,
             clean::FunctionItem(..) => ItemType::Function,
             clean::TypeAliasItem(..) => ItemType::TypeAlias,
-            clean::OpaqueTyItem(..) => ItemType::OpaqueTy,
             clean::StaticItem(..) => ItemType::Static,
             clean::ConstantItem(..) => ItemType::Constant,
             clean::TraitItem(..) => ItemType::Trait,
@@ -192,7 +190,6 @@ impl ItemType {
             ItemType::AssocConst => "associatedconstant",
             ItemType::ForeignType => "foreigntype",
             ItemType::Keyword => "keyword",
-            ItemType::OpaqueTy => "opaque",
             ItemType::ProcAttribute => "attr",
             ItemType::ProcDerive => "derive",
             ItemType::TraitAlias => "traitalias",
diff --git a/src/librustdoc/formats/mod.rs b/src/librustdoc/formats/mod.rs
index 0056fb48530..84adca8efa9 100644
--- a/src/librustdoc/formats/mod.rs
+++ b/src/librustdoc/formats/mod.rs
@@ -2,9 +2,8 @@ pub(crate) mod cache;
 pub(crate) mod item_type;
 pub(crate) mod renderer;
 
-use rustc_hir::def_id::DefId;
-
 pub(crate) use renderer::{run_format, FormatRenderer};
+use rustc_hir::def_id::DefId;
 
 use crate::clean::{self, ItemId};
 use crate::html::render::Context;
diff --git a/src/librustdoc/html/escape.rs b/src/librustdoc/html/escape.rs
index ea4b573aeb9..691f86847b5 100644
--- a/src/librustdoc/html/escape.rs
+++ b/src/librustdoc/html/escape.rs
@@ -5,6 +5,8 @@
 
 use std::fmt;
 
+use unicode_segmentation::UnicodeSegmentation;
+
 /// Wrapper struct which will emit the HTML-escaped version of the contained
 /// string when passed to a format string.
 pub(crate) struct Escape<'a>(pub &'a str);
@@ -74,3 +76,56 @@ impl<'a> fmt::Display for EscapeBodyText<'a> {
         Ok(())
     }
 }
+
+/// Wrapper struct which will emit the HTML-escaped version of the contained
+/// string when passed to a format string. This function also word-breaks
+/// CamelCase and snake_case word names.
+///
+/// This is only safe to use for text nodes. If you need your output to be
+/// safely contained in an attribute, use [`Escape`]. If you don't know the
+/// difference, use [`Escape`].
+pub(crate) struct EscapeBodyTextWithWbr<'a>(pub &'a str);
+
+impl<'a> fmt::Display for EscapeBodyTextWithWbr<'a> {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let EscapeBodyTextWithWbr(text) = *self;
+        if text.len() < 8 {
+            return EscapeBodyText(text).fmt(fmt);
+        }
+        let mut last = 0;
+        let mut it = text.grapheme_indices(true).peekable();
+        let _ = it.next(); // don't insert wbr before first char
+        while let Some((i, s)) = it.next() {
+            let pk = it.peek();
+            if s.chars().all(|c| c.is_whitespace()) {
+                // don't need "First <wbr>Second"; the space is enough
+                EscapeBodyText(&text[last..i]).fmt(fmt)?;
+                last = i;
+                continue;
+            }
+            let is_uppercase = || s.chars().any(|c| c.is_uppercase());
+            let next_is_uppercase =
+                || pk.map_or(true, |(_, t)| t.chars().any(|c| c.is_uppercase()));
+            let next_is_underscore = || pk.map_or(true, |(_, t)| t.contains('_'));
+            let next_is_colon = || pk.map_or(true, |(_, t)| t.contains(':'));
+            if i - last > 3 && is_uppercase() && !next_is_uppercase() {
+                EscapeBodyText(&text[last..i]).fmt(fmt)?;
+                fmt.write_str("<wbr>")?;
+                last = i;
+            } else if (s.contains(':') && !next_is_colon())
+                || (s.contains('_') && !next_is_underscore())
+            {
+                EscapeBodyText(&text[last..i + 1]).fmt(fmt)?;
+                fmt.write_str("<wbr>")?;
+                last = i + 1;
+            }
+        }
+        if last < text.len() {
+            EscapeBodyText(&text[last..]).fmt(fmt)?;
+        }
+        Ok(())
+    }
+}
+
+#[cfg(test)]
+mod tests;
diff --git a/src/librustdoc/html/escape/tests.rs b/src/librustdoc/html/escape/tests.rs
new file mode 100644
index 00000000000..a09649e9e18
--- /dev/null
+++ b/src/librustdoc/html/escape/tests.rs
@@ -0,0 +1,68 @@
+// basic examples
+#[test]
+fn escape_body_text_with_wbr() {
+    use super::EscapeBodyTextWithWbr as E;
+    // extreme corner cases
+    assert_eq!(&E("").to_string(), "");
+    assert_eq!(&E("a").to_string(), "a");
+    assert_eq!(&E("A").to_string(), "A");
+    assert_eq!(&E("_").to_string(), "_");
+    assert_eq!(&E(":").to_string(), ":");
+    assert_eq!(&E(" ").to_string(), " ");
+    assert_eq!(&E("___________").to_string(), "___________");
+    assert_eq!(&E(":::::::::::").to_string(), ":::::::::::");
+    assert_eq!(&E("           ").to_string(), "           ");
+    // real(istic) examples
+    assert_eq!(&E("FirstSecond").to_string(), "First<wbr>Second");
+    assert_eq!(&E("First_Second").to_string(), "First_<wbr>Second");
+    assert_eq!(&E("First Second").to_string(), "First Second");
+    assert_eq!(&E("First HSecond").to_string(), "First HSecond");
+    assert_eq!(&E("First HTTPSecond").to_string(), "First HTTP<wbr>Second");
+    assert_eq!(&E("First SecondThird").to_string(), "First Second<wbr>Third");
+    assert_eq!(&E("First<T>_Second").to_string(), "First&lt;<wbr>T&gt;_<wbr>Second");
+    assert_eq!(&E("first_second").to_string(), "first_<wbr>second");
+    assert_eq!(&E("first:second").to_string(), "first:<wbr>second");
+    assert_eq!(&E("first::second").to_string(), "first::<wbr>second");
+    assert_eq!(&E("MY_CONSTANT").to_string(), "MY_<wbr>CONSTANT");
+    // a string won't get wrapped if it's less than 8 bytes
+    assert_eq!(&E("HashSet").to_string(), "HashSet");
+    // an individual word won't get wrapped if it's less than 4 bytes
+    assert_eq!(&E("VecDequeue").to_string(), "VecDequeue");
+    assert_eq!(&E("VecDequeueSet").to_string(), "VecDequeue<wbr>Set");
+    // how to handle acronyms
+    assert_eq!(&E("BTreeMap").to_string(), "BTree<wbr>Map");
+    assert_eq!(&E("HTTPSProxy").to_string(), "HTTPS<wbr>Proxy");
+    // more corners
+    assert_eq!(&E("ṼẽçÑñéå").to_string(), "Ṽẽç<wbr>Ññéå");
+    assert_eq!(&E("V\u{0300}e\u{0300}c\u{0300}D\u{0300}e\u{0300}q\u{0300}u\u{0300}e\u{0300}u\u{0300}e\u{0300}").to_string(), "V\u{0300}e\u{0300}c\u{0300}<wbr>D\u{0300}e\u{0300}q\u{0300}u\u{0300}e\u{0300}u\u{0300}e\u{0300}");
+    assert_eq!(&E("LPFNACCESSIBLEOBJECTFROMWINDOW").to_string(), "LPFNACCESSIBLEOBJECTFROMWINDOW");
+}
+// property test
+#[test]
+fn escape_body_text_with_wbr_makes_sense() {
+    use itertools::Itertools as _;
+
+    use super::EscapeBodyTextWithWbr as E;
+    const C: [u8; 3] = [b'a', b'A', b'_'];
+    for chars in [
+        C.into_iter(),
+        C.into_iter(),
+        C.into_iter(),
+        C.into_iter(),
+        C.into_iter(),
+        C.into_iter(),
+        C.into_iter(),
+        C.into_iter(),
+    ]
+    .into_iter()
+    .multi_cartesian_product()
+    {
+        let s = String::from_utf8(chars).unwrap();
+        assert_eq!(s.len(), 8);
+        let esc = E(&s).to_string();
+        assert!(!esc.contains("<wbr><wbr>"));
+        assert!(!esc.ends_with("<wbr>"));
+        assert!(!esc.starts_with("<wbr>"));
+        assert_eq!(&esc.replace("<wbr>", ""), &s);
+    }
+}
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 055781f7fed..6357cfee141 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -12,11 +12,10 @@ use std::cell::Cell;
 use std::fmt::{self, Display, Write};
 use std::iter::{self, once};
 
-use rustc_ast as ast;
+use itertools::Itertools;
 use rustc_attr::{ConstStability, StabilityLevel, StableSince};
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_metadata::creader::{CStore, LoadedMacro};
@@ -25,21 +24,18 @@ use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::kw;
 use rustc_span::{sym, Symbol};
 use rustc_target::spec::abi::Abi;
+use {rustc_ast as ast, rustc_hir as hir};
 
-use itertools::Itertools;
-
-use crate::clean::{
-    self, types::ExternalLocation, utils::find_nearest_parent_module, ExternalCrate, PrimitiveType,
-};
+use super::url_parts_builder::{estimate_item_path_byte_length, UrlPartsBuilder};
+use crate::clean::types::ExternalLocation;
+use crate::clean::utils::find_nearest_parent_module;
+use crate::clean::{self, ExternalCrate, PrimitiveType};
 use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
-use crate::html::escape::Escape;
+use crate::html::escape::{Escape, EscapeBodyText};
 use crate::html::render::Context;
 use crate::passes::collect_intra_doc_links::UrlFragment;
 
-use super::url_parts_builder::estimate_item_path_byte_length;
-use super::url_parts_builder::UrlPartsBuilder;
-
 pub(crate) trait Print {
     fn print(self, buffer: &mut Buffer);
 }
@@ -375,7 +371,7 @@ impl clean::Lifetime {
     }
 }
 
-impl clean::Constant {
+impl clean::ConstantKind {
     pub(crate) fn print(&self, tcx: TyCtxt<'_>) -> impl Display + '_ {
         let expr = self.expr(tcx);
         display_fn(
@@ -992,6 +988,7 @@ pub(crate) fn anchor<'a, 'cx: 'a>(
                 f,
                 r#"<a class="{short_ty}" href="{url}" title="{short_ty} {path}">{text}</a>"#,
                 path = join_with_double_colon(&fqp),
+                text = EscapeBodyText(text.as_str()),
             )
         } else {
             f.write_str(text.as_str())
@@ -1009,6 +1006,7 @@ fn fmt_type<'cx>(
 
     match *t {
         clean::Generic(name) => f.write_str(name.as_str()),
+        clean::SelfTy => f.write_str("Self"),
         clean::Type::Path { ref path } => {
             // Paths like `T::Output` and `Self::Output` should be rendered with all segments.
             let did = path.def_id();
@@ -1287,9 +1285,8 @@ impl clean::Impl {
             f.write_str(" ")?;
 
             if let Some(ref ty) = self.trait_ {
-                match self.polarity {
-                    ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => {}
-                    ty::ImplPolarity::Negative => write!(f, "!")?,
+                if self.is_negative_trait_impl() {
+                    write!(f, "!")?;
                 }
                 ty.print(cx).fmt(f)?;
                 write!(f, " for ")?;
@@ -1455,29 +1452,22 @@ impl clean::FnDecl {
 
         let last_input_index = self.inputs.values.len().checked_sub(1);
         for (i, input) in self.inputs.values.iter().enumerate() {
-            if let Some(selfty) = input.to_self() {
+            if let Some(selfty) = input.to_receiver() {
                 match selfty {
-                    clean::SelfValue => {
+                    clean::SelfTy => {
                         write!(f, "self")?;
                     }
-                    clean::SelfBorrowed(Some(ref lt), mutability) => {
-                        write!(
-                            f,
-                            "{amp}{lifetime} {mutability}self",
-                            lifetime = lt.print(),
-                            mutability = mutability.print_with_space(),
-                        )?;
-                    }
-                    clean::SelfBorrowed(None, mutability) => {
-                        write!(
-                            f,
-                            "{amp}{mutability}self",
-                            mutability = mutability.print_with_space(),
-                        )?;
+                    clean::BorrowedRef { lifetime, mutability, type_: box clean::SelfTy } => {
+                        write!(f, "{amp}")?;
+                        match lifetime {
+                            Some(lt) => write!(f, "{lt} ", lt = lt.print())?,
+                            None => {}
+                        }
+                        write!(f, "{mutability}self", mutability = mutability.print_with_space())?;
                     }
-                    clean::SelfExplicit(ref typ) => {
+                    _ => {
                         write!(f, "self: ")?;
-                        typ.print(cx).fmt(f)?;
+                        selfty.print(cx).fmt(f)?;
                     }
                 }
             } else {
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 336d18a1df1..29b4889a6ab 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -5,10 +5,6 @@
 //!
 //! Use the `render_with_highlighting` to highlight some rust code.
 
-use crate::clean::PrimitiveType;
-use crate::html::escape::EscapeBodyText;
-use crate::html::render::{Context, LinkFromSrc};
-
 use std::collections::VecDeque;
 use std::fmt::{Display, Write};
 
@@ -19,6 +15,9 @@ use rustc_span::symbol::Symbol;
 use rustc_span::{BytePos, Span, DUMMY_SP};
 
 use super::format::{self, Buffer};
+use crate::clean::PrimitiveType;
+use crate::html::escape::EscapeBodyText;
+use crate::html::render::{Context, LinkFromSrc};
 
 /// This type is needed in case we want to render links on items to allow to go to their definition.
 pub(crate) struct HrefContext<'a, 'tcx> {
diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs
index 4c0874a686f..9d511018dec 100644
--- a/src/librustdoc/html/highlight/tests.rs
+++ b/src/librustdoc/html/highlight/tests.rs
@@ -1,9 +1,10 @@
-use super::{write_code, DecorationInfo};
-use crate::html::format::Buffer;
 use expect_test::expect_file;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_span::create_default_session_globals_then;
 
+use super::{write_code, DecorationInfo};
+use crate::html::format::Buffer;
+
 const STYLE: &str = r#"
 <style>
 .kw { color: #8959A8; }
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index 22576b76e41..780cda9b1cd 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -1,15 +1,13 @@
 use std::path::PathBuf;
 
+use rinja::Template;
 use rustc_data_structures::fx::FxHashMap;
 
+use super::static_files::{StaticFiles, STATIC_FILES};
 use crate::externalfiles::ExternalHtml;
 use crate::html::format::{Buffer, Print};
 use crate::html::render::{ensure_trailing_slash, StylePath};
 
-use rinja::Template;
-
-use super::static_files::{StaticFiles, STATIC_FILES};
-
 #[derive(Clone)]
 pub(crate) struct Layout {
     pub(crate) logo: String,
@@ -71,6 +69,8 @@ struct PageLayout<'a> {
     display_krate_version_extra: &'a str,
 }
 
+pub(crate) use crate::html::render::sidebar::filters;
+
 pub(crate) fn render<T: Print, S: Print>(
     layout: &Layout,
     page: &Page<'_>,
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index a7f0df5afa9..c41db654112 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -25,15 +25,6 @@
 //! // ... something using html
 //! ```
 
-use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{Diag, DiagMessage};
-use rustc_hir::def_id::DefId;
-use rustc_middle::ty::TyCtxt;
-pub(crate) use rustc_resolve::rustdoc::main_body_opts;
-use rustc_resolve::rustdoc::may_be_doc_link;
-use rustc_span::edition::Edition;
-use rustc_span::{Span, Symbol};
-
 use std::borrow::Cow;
 use std::collections::VecDeque;
 use std::fmt::Write;
@@ -43,6 +34,19 @@ use std::path::PathBuf;
 use std::str::{self, CharIndices};
 use std::sync::OnceLock;
 
+use pulldown_cmark::{
+    html, BrokenLink, BrokenLinkCallback, CodeBlockKind, CowStr, Event, LinkType, OffsetIter,
+    Options, Parser, Tag, TagEnd,
+};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::{Diag, DiagMessage};
+use rustc_hir::def_id::DefId;
+use rustc_middle::ty::TyCtxt;
+pub(crate) use rustc_resolve::rustdoc::main_body_opts;
+use rustc_resolve::rustdoc::may_be_doc_link;
+use rustc_span::edition::Edition;
+use rustc_span::{Span, Symbol};
+
 use crate::clean::RenderedLink;
 use crate::doctest;
 use crate::doctest::GlobalTestOptions;
@@ -53,11 +57,6 @@ use crate::html::length_limit::HtmlWithLimit;
 use crate::html::render::small_url_encode;
 use crate::html::toc::TocBuilder;
 
-use pulldown_cmark::{
-    html, BrokenLink, BrokenLinkCallback, CodeBlockKind, CowStr, Event, LinkType, OffsetIter,
-    Options, Parser, Tag, TagEnd,
-};
-
 #[cfg(test)]
 mod tests;
 
@@ -305,7 +304,8 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
             Some(format!(
                 "<a class=\"test-arrow\" \
                     target=\"_blank\" \
-                    href=\"{url}?code={test_escaped}{channel}&amp;edition={edition}\">Run</a>",
+                    title=\"Run code\" \
+                    href=\"{url}?code={test_escaped}{channel}&amp;edition={edition}\"></a>",
             ))
         });
 
@@ -925,6 +925,7 @@ pub(crate) struct TagIterator<'a, 'tcx> {
     data: &'a str,
     is_in_attribute_block: bool,
     extra: Option<&'a ExtraInfo<'tcx>>,
+    is_error: bool,
 }
 
 #[derive(Clone, Debug, Eq, PartialEq)]
@@ -951,13 +952,20 @@ struct Indices {
 
 impl<'a, 'tcx> TagIterator<'a, 'tcx> {
     pub(crate) fn new(data: &'a str, extra: Option<&'a ExtraInfo<'tcx>>) -> Self {
-        Self { inner: data.char_indices().peekable(), data, is_in_attribute_block: false, extra }
+        Self {
+            inner: data.char_indices().peekable(),
+            data,
+            is_in_attribute_block: false,
+            extra,
+            is_error: false,
+        }
     }
 
-    fn emit_error(&self, err: impl Into<DiagMessage>) {
+    fn emit_error(&mut self, err: impl Into<DiagMessage>) {
         if let Some(extra) = self.extra {
             extra.error_invalid_codeblock_attr(err);
         }
+        self.is_error = true;
     }
 
     fn skip_separators(&mut self) -> Option<usize> {
@@ -1155,6 +1163,9 @@ impl<'a, 'tcx> Iterator for TagIterator<'a, 'tcx> {
     type Item = LangStringToken<'a>;
 
     fn next(&mut self) -> Option<Self::Item> {
+        if self.is_error {
+            return None;
+        }
         let Some(start) = self.skip_separators() else {
             if self.is_in_attribute_block {
                 self.emit_error("unclosed attribute block (`{}`): missing `}` at the end");
@@ -1343,14 +1354,15 @@ impl LangString {
             }
         };
 
-        call(&mut TagIterator::new(string, extra));
+        let mut tag_iter = TagIterator::new(string, extra);
+        call(&mut tag_iter);
 
         // ignore-foo overrides ignore
         if !ignores.is_empty() {
             data.ignore = Ignore::Some(ignores);
         }
 
-        data.rust &= !seen_custom_tag && (!seen_other_tags || seen_rust_tags);
+        data.rust &= !seen_custom_tag && (!seen_other_tags || seen_rust_tags) && !tag_iter.is_error;
 
         data
     }
diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs
index fb74c079c9a..e490099a92e 100644
--- a/src/librustdoc/html/markdown/tests.rs
+++ b/src/librustdoc/html/markdown/tests.rs
@@ -1,9 +1,9 @@
-use super::{find_testable_code, plain_text_summary, short_markdown_summary};
+use rustc_span::edition::{Edition, DEFAULT_EDITION};
+
 use super::{
-    ErrorCodes, HeadingOffset, IdMap, Ignore, LangString, LangStringToken, Markdown,
-    MarkdownItemInfo, TagIterator,
+    find_testable_code, plain_text_summary, short_markdown_summary, ErrorCodes, HeadingOffset,
+    IdMap, Ignore, LangString, LangStringToken, Markdown, MarkdownItemInfo, TagIterator,
 };
-use rustc_span::edition::{Edition, DEFAULT_EDITION};
 
 #[test]
 fn test_unique_id() {
@@ -61,7 +61,7 @@ fn test_lang_string_parse() {
         ..Default::default()
     });
     // error
-    t(LangString { original: "{rust}".into(), rust: true, ..Default::default() });
+    t(LangString { original: "{rust}".into(), rust: false, ..Default::default() });
     t(LangString {
         original: "{.rust}".into(),
         rust: true,
@@ -233,7 +233,7 @@ fn test_lang_string_parse() {
         ..Default::default()
     });
     // error
-    t(LangString { original: "{class=first=second}".into(), rust: true, ..Default::default() });
+    t(LangString { original: "{class=first=second}".into(), rust: false, ..Default::default() });
     // error
     t(LangString {
         original: "{class=first.second}".into(),
@@ -261,7 +261,7 @@ fn test_lang_string_parse() {
         ..Default::default()
     });
     // error
-    t(LangString { original: r#"{class=f"irst"}"#.into(), rust: true, ..Default::default() });
+    t(LangString { original: r#"{class=f"irst"}"#.into(), rust: false, ..Default::default() });
 }
 
 #[test]
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 7718413c956..0334eacc161 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -5,6 +5,7 @@ use std::path::{Path, PathBuf};
 use std::rc::Rc;
 use std::sync::mpsc::{channel, Receiver};
 
+use rinja::Template;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def_id::{DefIdMap, LOCAL_CRATE};
 use rustc_middle::ty::TyCtxt;
@@ -14,15 +15,12 @@ use rustc_span::{sym, FileName, Symbol};
 
 use super::print_item::{full_path, item_path, print_item};
 use super::search_index::build_index;
+use super::sidebar::{print_sidebar, sidebar_module_like, Sidebar};
 use super::write_shared::write_shared;
-use super::{
-    collect_spans_and_sources, scrape_examples_help,
-    sidebar::print_sidebar,
-    sidebar::{sidebar_module_like, Sidebar},
-    AllTypes, LinkFromSrc, StylePath,
-};
+use super::{collect_spans_and_sources, scrape_examples_help, AllTypes, LinkFromSrc, StylePath};
+use crate::clean::types::ExternalLocation;
 use crate::clean::utils::has_doc_flag;
-use crate::clean::{self, types::ExternalLocation, ExternalCrate};
+use crate::clean::{self, ExternalCrate};
 use crate::config::{ModuleSorting, RenderOptions};
 use crate::docfs::{DocFS, PathError};
 use crate::error::Error;
@@ -36,7 +34,6 @@ use crate::html::url_parts_builder::UrlPartsBuilder;
 use crate::html::{layout, sources, static_files};
 use crate::scrape_examples::AllCallLocations;
 use crate::try_err;
-use rinja::Template;
 
 /// Major driving force in all rustdoc rendering. This contains information
 /// about where in the tree-like hierarchy rendering is occurring and controls
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 5b9ef67109c..7ce637d3ab4 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -30,21 +30,17 @@ mod tests;
 
 mod context;
 mod print_item;
-mod sidebar;
+pub(crate) mod sidebar;
 mod span_map;
 mod type_layout;
 mod write_shared;
 
-pub(crate) use self::context::*;
-pub(crate) use self::span_map::{collect_spans_and_sources, LinkFromSrc};
-
 use std::collections::VecDeque;
 use std::fmt::{self, Write};
-use std::fs;
 use std::iter::Peekable;
 use std::path::PathBuf;
 use std::rc::Rc;
-use std::str;
+use std::{fs, str};
 
 use rinja::Template;
 use rustc_attr::{ConstStability, DeprecatedSince, Deprecation, StabilityLevel, StableSince};
@@ -55,14 +51,14 @@ use rustc_hir::Mutability;
 use rustc_middle::ty::print::PrintTraitRefExt;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::RustcVersion;
-use rustc_span::{
-    symbol::{sym, Symbol},
-    BytePos, FileName, RealFileName, DUMMY_SP,
-};
+use rustc_span::symbol::{sym, Symbol};
+use rustc_span::{BytePos, FileName, RealFileName, DUMMY_SP};
 use serde::ser::SerializeMap;
 use serde::{Serialize, Serializer};
 
-use crate::clean::{self, ItemId, RenderedLink, SelfTy};
+pub(crate) use self::context::*;
+pub(crate) use self::span_map::{collect_spans_and_sources, LinkFromSrc};
+use crate::clean::{self, ItemId, RenderedLink};
 use crate::error::Error;
 use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
@@ -73,15 +69,13 @@ use crate::html::format::{
     print_default_space, print_generic_bounds, print_where_clause, visibility_print_with_space,
     Buffer, Ending, HrefError, PrintWithSpace,
 };
-use crate::html::highlight;
 use crate::html::markdown::{
     HeadingOffset, IdMap, Markdown, MarkdownItemInfo, MarkdownSummaryLine,
 };
-use crate::html::sources;
 use crate::html::static_files::SCRAPE_EXAMPLES_HELP_MD;
+use crate::html::{highlight, sources};
 use crate::scrape_examples::{CallData, CallLocation};
-use crate::try_none;
-use crate::DOC_RUST_LANG_ORG_CHANNEL;
+use crate::{try_none, DOC_RUST_LANG_ORG_CHANNEL};
 
 pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ {
     crate::html::format::display_fn(move |f| {
@@ -338,7 +332,6 @@ struct AllTypes {
     macros: FxHashSet<ItemEntry>,
     functions: FxHashSet<ItemEntry>,
     type_aliases: FxHashSet<ItemEntry>,
-    opaque_tys: FxHashSet<ItemEntry>,
     statics: FxHashSet<ItemEntry>,
     constants: FxHashSet<ItemEntry>,
     attribute_macros: FxHashSet<ItemEntry>,
@@ -358,7 +351,6 @@ impl AllTypes {
             macros: new_set(100),
             functions: new_set(100),
             type_aliases: new_set(100),
-            opaque_tys: new_set(100),
             statics: new_set(100),
             constants: new_set(100),
             attribute_macros: new_set(100),
@@ -382,7 +374,6 @@ impl AllTypes {
                 ItemType::Macro => self.macros.insert(ItemEntry::new(new_url, name)),
                 ItemType::Function => self.functions.insert(ItemEntry::new(new_url, name)),
                 ItemType::TypeAlias => self.type_aliases.insert(ItemEntry::new(new_url, name)),
-                ItemType::OpaqueTy => self.opaque_tys.insert(ItemEntry::new(new_url, name)),
                 ItemType::Static => self.statics.insert(ItemEntry::new(new_url, name)),
                 ItemType::Constant => self.constants.insert(ItemEntry::new(new_url, name)),
                 ItemType::ProcAttribute => {
@@ -422,9 +413,6 @@ impl AllTypes {
         if !self.type_aliases.is_empty() {
             sections.insert(ItemSection::TypeAliases);
         }
-        if !self.opaque_tys.is_empty() {
-            sections.insert(ItemSection::OpaqueTypes);
-        }
         if !self.statics.is_empty() {
             sections.insert(ItemSection::Statics);
         }
@@ -478,7 +466,6 @@ impl AllTypes {
         print_entries(f, &self.functions, ItemSection::Functions);
         print_entries(f, &self.type_aliases, ItemSection::TypeAliases);
         print_entries(f, &self.trait_aliases, ItemSection::TraitAliases);
-        print_entries(f, &self.opaque_tys, ItemSection::OpaqueTypes);
         print_entries(f, &self.statics, ItemSection::Statics);
         print_entries(f, &self.constants, ItemSection::Constants);
     }
@@ -1090,22 +1077,26 @@ fn render_assoc_item(
         clean::MethodItem(m, _) => {
             assoc_method(w, item, &m.generics, &m.decl, link, parent, cx, render_mode)
         }
-        kind @ (clean::TyAssocConstItem(generics, ty) | clean::AssocConstItem(generics, ty, _)) => {
-            assoc_const(
-                w,
-                item,
-                generics,
-                ty,
-                match kind {
-                    clean::TyAssocConstItem(..) => None,
-                    clean::AssocConstItem(.., default) => Some(default),
-                    _ => unreachable!(),
-                },
-                link,
-                if parent == ItemType::Trait { 4 } else { 0 },
-                cx,
-            )
-        }
+        clean::TyAssocConstItem(generics, ty) => assoc_const(
+            w,
+            item,
+            generics,
+            ty,
+            None,
+            link,
+            if parent == ItemType::Trait { 4 } else { 0 },
+            cx,
+        ),
+        clean::AssocConstItem(ci) => assoc_const(
+            w,
+            item,
+            &ci.generics,
+            &ci.type_,
+            Some(&ci.kind),
+            link,
+            if parent == ItemType::Trait { 4 } else { 0 },
+            cx,
+        ),
         clean::TyAssocTypeItem(ref generics, ref bounds) => assoc_type(
             w,
             item,
@@ -1381,21 +1372,20 @@ fn render_deref_methods(
 
 fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> bool {
     let self_type_opt = match *item.kind {
-        clean::MethodItem(ref method, _) => method.decl.self_type(),
-        clean::TyMethodItem(ref method) => method.decl.self_type(),
+        clean::MethodItem(ref method, _) => method.decl.receiver_type(),
+        clean::TyMethodItem(ref method) => method.decl.receiver_type(),
         _ => None,
     };
 
     if let Some(self_ty) = self_type_opt {
-        let (by_mut_ref, by_box, by_value) = match self_ty {
-            SelfTy::SelfBorrowed(_, mutability)
-            | SelfTy::SelfExplicit(clean::BorrowedRef { mutability, .. }) => {
+        let (by_mut_ref, by_box, by_value) = match *self_ty {
+            clean::Type::BorrowedRef { mutability, .. } => {
                 (mutability == Mutability::Mut, false, false)
             }
-            SelfTy::SelfExplicit(clean::Type::Path { path }) => {
+            clean::Type::Path { ref path } => {
                 (false, Some(path.def_id()) == tcx.lang_items().owned_box(), false)
             }
-            SelfTy::SelfValue => (false, false, true),
+            clean::Type::SelfTy => (false, false, true),
             _ => (false, false, false),
         };
 
@@ -1690,8 +1680,7 @@ fn render_impl(
                     w.write_str("</h4></section>");
                 }
             }
-            kind @ (clean::TyAssocConstItem(generics, ty)
-            | clean::AssocConstItem(generics, ty, _)) => {
+            clean::TyAssocConstItem(generics, ty) => {
                 let source_id = format!("{item_type}.{name}");
                 let id = cx.derive_id(&source_id);
                 write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">");
@@ -1706,11 +1695,29 @@ fn render_impl(
                     item,
                     generics,
                     ty,
-                    match kind {
-                        clean::TyAssocConstItem(..) => None,
-                        clean::AssocConstItem(.., default) => Some(default),
-                        _ => unreachable!(),
-                    },
+                    None,
+                    link.anchor(if trait_.is_some() { &source_id } else { &id }),
+                    0,
+                    cx,
+                );
+                w.write_str("</h4></section>");
+            }
+            clean::AssocConstItem(ci) => {
+                let source_id = format!("{item_type}.{name}");
+                let id = cx.derive_id(&source_id);
+                write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">");
+                render_rightside(w, cx, item, render_mode);
+                if trait_.is_some() {
+                    // Anchors are only used on trait impls.
+                    write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>");
+                }
+                w.write_str("<h4 class=\"code-header\">");
+                assoc_const(
+                    w,
+                    item,
+                    &ci.generics,
+                    &ci.type_,
+                    Some(&ci.kind),
                     link.anchor(if trait_.is_some() { &source_id } else { &id }),
                     0,
                     cx,
@@ -1773,20 +1780,23 @@ fn render_impl(
 
     let mut impl_items = Buffer::empty_from(w);
     let mut default_impl_items = Buffer::empty_from(w);
+    let impl_ = i.inner_impl();
 
-    for trait_item in &i.inner_impl().items {
-        doc_impl_item(
-            &mut default_impl_items,
-            &mut impl_items,
-            cx,
-            trait_item,
-            if trait_.is_some() { &i.impl_item } else { parent },
-            link,
-            render_mode,
-            false,
-            trait_,
-            rendering_params,
-        );
+    if !impl_.is_negative_trait_impl() {
+        for trait_item in &impl_.items {
+            doc_impl_item(
+                &mut default_impl_items,
+                &mut impl_items,
+                cx,
+                trait_item,
+                if trait_.is_some() { &i.impl_item } else { parent },
+                link,
+                render_mode,
+                false,
+                trait_,
+                rendering_params,
+            );
+        }
     }
 
     fn render_default_items(
@@ -1837,13 +1847,15 @@ fn render_impl(
     // We don't emit documentation for default items if they appear in the
     // Implementations on Foreign Types or Implementors sections.
     if rendering_params.show_default_items {
-        if let Some(t) = trait_ {
+        if let Some(t) = trait_
+            && !impl_.is_negative_trait_impl()
+        {
             render_default_items(
                 &mut default_impl_items,
                 &mut impl_items,
                 cx,
                 t,
-                i.inner_impl(),
+                impl_,
                 &i.impl_item,
                 render_mode,
                 rendering_params,
@@ -1875,7 +1887,7 @@ fn render_impl(
         }
 
         if let Some(ref dox) = i.impl_item.opt_doc_value() {
-            if trait_.is_none() && i.inner_impl().items.is_empty() {
+            if trait_.is_none() && impl_.items.is_empty() {
                 w.write_str(
                     "<div class=\"item-info\">\
                          <div class=\"stab empty-impl\">This impl block contains no items.</div>\
@@ -2160,7 +2172,6 @@ pub(crate) enum ItemSection {
     AssociatedConstants,
     ForeignTypes,
     Keywords,
-    OpaqueTypes,
     AttributeMacros,
     DeriveMacros,
     TraitAliases,
@@ -2193,7 +2204,6 @@ impl ItemSection {
             AssociatedConstants,
             ForeignTypes,
             Keywords,
-            OpaqueTypes,
             AttributeMacros,
             DeriveMacros,
             TraitAliases,
@@ -2223,7 +2233,6 @@ impl ItemSection {
             Self::AssociatedConstants => "associated-consts",
             Self::ForeignTypes => "foreign-types",
             Self::Keywords => "keywords",
-            Self::OpaqueTypes => "opaque-types",
             Self::AttributeMacros => "attributes",
             Self::DeriveMacros => "derives",
             Self::TraitAliases => "trait-aliases",
@@ -2253,7 +2262,6 @@ impl ItemSection {
             Self::AssociatedConstants => "Associated Constants",
             Self::ForeignTypes => "Foreign Types",
             Self::Keywords => "Keywords",
-            Self::OpaqueTypes => "Opaque Types",
             Self::AttributeMacros => "Attribute Macros",
             Self::DeriveMacros => "Derive Macros",
             Self::TraitAliases => "Trait Aliases",
@@ -2284,7 +2292,6 @@ fn item_ty_to_section(ty: ItemType) -> ItemSection {
         ItemType::AssocConst => ItemSection::AssociatedConstants,
         ItemType::ForeignType => ItemSection::ForeignTypes,
         ItemType::Keyword => ItemSection::Keywords,
-        ItemType::OpaqueTy => ItemSection::OpaqueTypes,
         ItemType::ProcAttribute => ItemSection::AttributeMacros,
         ItemType::ProcDerive => ItemSection::DeriveMacros,
         ItemType::TraitAlias => ItemSection::TraitAliases,
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index cf78a1d223c..d8b111471b8 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -1,3 +1,10 @@
+use std::cell::{RefCell, RefMut};
+use std::cmp::Ordering;
+use std::fmt;
+use std::rc::Rc;
+
+use itertools::Itertools;
+use rinja::Template;
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
@@ -8,10 +15,6 @@ use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_target::abi::VariantIdx;
-use std::cell::{RefCell, RefMut};
-use std::cmp::Ordering;
-use std::fmt;
-use std::rc::Rc;
 
 use super::type_layout::document_type_layout;
 use super::{
@@ -26,7 +29,7 @@ use crate::clean;
 use crate::config::ModuleSorting;
 use crate::formats::item_type::ItemType;
 use crate::formats::Impl;
-use crate::html::escape::Escape;
+use crate::html::escape::{Escape, EscapeBodyTextWithWbr};
 use crate::html::format::{
     display_fn, join_with_double_colon, print_abi_with_space, print_constness_with_space,
     print_where_clause, visibility_print_with_space, Buffer, Ending, PrintWithSpace,
@@ -36,9 +39,6 @@ use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine};
 use crate::html::render::{document_full, document_item_info};
 use crate::html::url_parts_builder::UrlPartsBuilder;
 
-use itertools::Itertools;
-use rinja::Template;
-
 /// Generates a Rinja template struct for rendering items with common methods.
 ///
 /// Usage:
@@ -202,7 +202,6 @@ pub(super) fn print_item(cx: &mut Context<'_>, item: &clean::Item, buf: &mut Buf
         clean::ConstantItem(..) => "Constant ",
         clean::ForeignTypeItem => "Foreign Type ",
         clean::KeywordItem => "Keyword ",
-        clean::OpaqueTyItem(..) => "Opaque Type ",
         clean::TraitAliasItem(..) => "Trait Alias ",
         _ => {
             // We don't generate pages for any other type.
@@ -267,10 +266,9 @@ pub(super) fn print_item(cx: &mut Context<'_>, item: &clean::Item, buf: &mut Buf
         clean::PrimitiveItem(_) => item_primitive(buf, cx, item),
         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::ConstantItem(ci) => item_constant(buf, cx, item, &ci.generics, &ci.type_, &ci.kind),
         clean::ForeignTypeItem => item_foreign_type(buf, cx, item),
         clean::KeywordItem => item_keyword(buf, cx, item),
-        clean::OpaqueTyItem(ref e) => item_opaque_ty(buf, cx, item, e),
         clean::TraitAliasItem(ref ta) => item_trait_alias(buf, cx, item, ta),
         _ => {
             // We don't generate pages for any other type.
@@ -423,7 +421,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
                         "<div class=\"item-name\"><code>{}extern crate {} as {};",
                         visibility_print_with_space(myitem, cx),
                         anchor(myitem.item_id.expect_def_id(), src, cx),
-                        myitem.name.unwrap(),
+                        EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()),
                     ),
                     None => write!(
                         w,
@@ -520,7 +518,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
                         {stab_tags}\
                      </div>\
                      {docs_before}{docs}{docs_after}",
-                    name = myitem.name.unwrap(),
+                    name = EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()),
                     visibility_and_hidden = visibility_and_hidden,
                     stab_tags = extra_info_tags(myitem, item, tcx),
                     class = myitem.type_(),
@@ -558,7 +556,7 @@ fn extra_info_tags<'a, 'tcx: 'a>(
             display_fn(move |f| {
                 write!(
                     f,
-                    r#"<span class="stab {class}" title="{title}">{contents}</span>"#,
+                    r#"<wbr><span class="stab {class}" title="{title}">{contents}</span>"#,
                     title = Escape(title),
                 )
             })
@@ -1197,35 +1195,6 @@ fn item_trait_alias(
         .unwrap();
 }
 
-fn item_opaque_ty(
-    w: &mut impl fmt::Write,
-    cx: &mut Context<'_>,
-    it: &clean::Item,
-    t: &clean::OpaqueTy,
-) {
-    wrap_item(w, |w| {
-        write!(
-            w,
-            "{attrs}type {name}{generics}{where_clause} = impl {bounds};",
-            attrs = render_attributes_in_pre(it, "", cx),
-            name = it.name.unwrap(),
-            generics = t.generics.print(cx),
-            where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline),
-            bounds = bounds(&t.bounds, false, cx),
-        )
-        .unwrap();
-    });
-
-    write!(w, "{}", document(cx, it, None, HeadingOffset::H2)).unwrap();
-
-    // Render any items associated directly to this alias, as otherwise they
-    // won't be visible anywhere in the docs. It would be nice to also show
-    // associated items from the aliased type (see discussion in #32077), but
-    // we need #14072 to make sense of the generics.
-    write!(w, "{}", render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All))
-        .unwrap();
-}
-
 fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::TypeAlias) {
     wrap_item(w, |w| {
         write!(
@@ -1841,7 +1810,7 @@ fn item_constant(
     it: &clean::Item,
     generics: &clean::Generics,
     ty: &clean::Type,
-    c: &clean::Constant,
+    c: &clean::ConstantKind,
 ) {
     wrap_item(w, |w| {
         let tcx = cx.tcx();
@@ -1911,7 +1880,7 @@ fn item_fields(
     w: &mut Buffer,
     cx: &mut Context<'_>,
     it: &clean::Item,
-    fields: &Vec<clean::Item>,
+    fields: &[clean::Item],
     ctor_kind: Option<CtorKind>,
 ) {
     let mut fields = fields
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index 66d3f0fd8ce..8a2f31f7413 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -3,6 +3,7 @@ pub(crate) mod encode;
 use std::collections::hash_map::Entry;
 use std::collections::{BTreeMap, VecDeque};
 
+use encode::{bitmap_to_string, write_vlqhex_to_string};
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::DefId;
@@ -19,8 +20,6 @@ use crate::html::format::join_with_double_colon;
 use crate::html::markdown::short_markdown_summary;
 use crate::html::render::{self, IndexItem, IndexItemFunctionType, RenderType, RenderTypeId};
 
-use encode::{bitmap_to_string, write_vlqhex_to_string};
-
 /// The serialized search description sharded version
 ///
 /// The `index` is a JSON-encoded list of names and other information.
@@ -798,7 +797,11 @@ fn get_index_type_id(
             }
         }
         // Not supported yet
-        clean::Type::Pat(..) | clean::Generic(_) | clean::ImplTrait(_) | clean::Infer => None,
+        clean::Type::Pat(..)
+        | clean::Generic(_)
+        | clean::SelfTy
+        | clean::ImplTrait(_)
+        | clean::Infer => None,
     }
 }
 
@@ -851,34 +854,70 @@ fn simplify_fn_type<'tcx, 'a>(
 
     // If this argument is a type parameter and not a trait bound or a type, we need to look
     // for its bounds.
-    if let Type::Generic(arg_s) = *arg {
-        // First we check if the bounds are in a `where` predicate...
-        let mut type_bounds = Vec::new();
-        for where_pred in generics.where_predicates.iter().filter(|g| match g {
-            WherePredicate::BoundPredicate { ty: Type::Generic(ty_s), .. } => *ty_s == arg_s,
-            _ => false,
-        }) {
-            let bounds = where_pred.get_bounds().unwrap_or_else(|| &[]);
-            for bound in bounds.iter() {
-                if let Some(path) = bound.get_trait_path() {
-                    let ty = Type::Path { path };
-                    simplify_fn_type(
-                        self_,
-                        generics,
-                        &ty,
-                        tcx,
-                        recurse + 1,
-                        &mut type_bounds,
-                        rgen,
-                        is_return,
-                        cache,
-                    );
+    match *arg {
+        Type::Generic(arg_s) => {
+            // First we check if the bounds are in a `where` predicate...
+            let mut type_bounds = Vec::new();
+            for where_pred in generics.where_predicates.iter().filter(|g| match g {
+                WherePredicate::BoundPredicate { ty, .. } => *ty == *arg,
+                _ => false,
+            }) {
+                let bounds = where_pred.get_bounds().unwrap_or_else(|| &[]);
+                for bound in bounds.iter() {
+                    if let Some(path) = bound.get_trait_path() {
+                        let ty = Type::Path { path };
+                        simplify_fn_type(
+                            self_,
+                            generics,
+                            &ty,
+                            tcx,
+                            recurse + 1,
+                            &mut type_bounds,
+                            rgen,
+                            is_return,
+                            cache,
+                        );
+                    }
+                }
+            }
+            // Otherwise we check if the trait bounds are "inlined" like `T: Option<u32>`...
+            if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) {
+                for bound in bound.get_bounds().unwrap_or(&[]) {
+                    if let Some(path) = bound.get_trait_path() {
+                        let ty = Type::Path { path };
+                        simplify_fn_type(
+                            self_,
+                            generics,
+                            &ty,
+                            tcx,
+                            recurse + 1,
+                            &mut type_bounds,
+                            rgen,
+                            is_return,
+                            cache,
+                        );
+                    }
                 }
             }
+            if let Some((idx, _)) = rgen.get(&SimplifiedParam::Symbol(arg_s)) {
+                res.push(RenderType {
+                    id: Some(RenderTypeId::Index(*idx)),
+                    generics: None,
+                    bindings: None,
+                });
+            } else {
+                let idx = -isize::try_from(rgen.len() + 1).unwrap();
+                rgen.insert(SimplifiedParam::Symbol(arg_s), (idx, type_bounds));
+                res.push(RenderType {
+                    id: Some(RenderTypeId::Index(idx)),
+                    generics: None,
+                    bindings: None,
+                });
+            }
         }
-        // Otherwise we check if the trait bounds are "inlined" like `T: Option<u32>`...
-        if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) {
-            for bound in bound.get_bounds().unwrap_or(&[]) {
+        Type::ImplTrait(ref bounds) => {
+            let mut type_bounds = Vec::new();
+            for bound in bounds {
                 if let Some(path) = bound.get_trait_path() {
                     let ty = Type::Path { path };
                     simplify_fn_type(
@@ -894,84 +933,22 @@ fn simplify_fn_type<'tcx, 'a>(
                     );
                 }
             }
-        }
-        if let Some((idx, _)) = rgen.get(&SimplifiedParam::Symbol(arg_s)) {
-            res.push(RenderType {
-                id: Some(RenderTypeId::Index(*idx)),
-                generics: None,
-                bindings: None,
-            });
-        } else {
-            let idx = -isize::try_from(rgen.len() + 1).unwrap();
-            rgen.insert(SimplifiedParam::Symbol(arg_s), (idx, type_bounds));
-            res.push(RenderType {
-                id: Some(RenderTypeId::Index(idx)),
-                generics: None,
-                bindings: None,
-            });
-        }
-    } else if let Type::ImplTrait(ref bounds) = *arg {
-        let mut type_bounds = Vec::new();
-        for bound in bounds {
-            if let Some(path) = bound.get_trait_path() {
-                let ty = Type::Path { path };
-                simplify_fn_type(
-                    self_,
-                    generics,
-                    &ty,
-                    tcx,
-                    recurse + 1,
-                    &mut type_bounds,
-                    rgen,
-                    is_return,
-                    cache,
-                );
+            if is_return && !type_bounds.is_empty() {
+                // In return position, `impl Trait` is a unique thing.
+                res.push(RenderType { id: None, generics: Some(type_bounds), bindings: None });
+            } else {
+                // In parameter position, `impl Trait` is the same as an unnamed generic parameter.
+                let idx = -isize::try_from(rgen.len() + 1).unwrap();
+                rgen.insert(SimplifiedParam::Anonymous(idx), (idx, type_bounds));
+                res.push(RenderType {
+                    id: Some(RenderTypeId::Index(idx)),
+                    generics: None,
+                    bindings: None,
+                });
             }
         }
-        if is_return && !type_bounds.is_empty() {
-            // In parameter position, `impl Trait` is a unique thing.
-            res.push(RenderType { id: None, generics: Some(type_bounds), bindings: None });
-        } else {
-            // In parameter position, `impl Trait` is the same as an unnamed generic parameter.
-            let idx = -isize::try_from(rgen.len() + 1).unwrap();
-            rgen.insert(SimplifiedParam::Anonymous(idx), (idx, type_bounds));
-            res.push(RenderType {
-                id: Some(RenderTypeId::Index(idx)),
-                generics: None,
-                bindings: None,
-            });
-        }
-    } else if let Type::Slice(ref ty) = *arg {
-        let mut ty_generics = Vec::new();
-        simplify_fn_type(
-            self_,
-            generics,
-            &ty,
-            tcx,
-            recurse + 1,
-            &mut ty_generics,
-            rgen,
-            is_return,
-            cache,
-        );
-        res.push(get_index_type(arg, ty_generics, rgen));
-    } else if let Type::Array(ref ty, _) = *arg {
-        let mut ty_generics = Vec::new();
-        simplify_fn_type(
-            self_,
-            generics,
-            &ty,
-            tcx,
-            recurse + 1,
-            &mut ty_generics,
-            rgen,
-            is_return,
-            cache,
-        );
-        res.push(get_index_type(arg, ty_generics, rgen));
-    } else if let Type::Tuple(ref tys) = *arg {
-        let mut ty_generics = Vec::new();
-        for ty in tys {
+        Type::Slice(ref ty) => {
+            let mut ty_generics = Vec::new();
             simplify_fn_type(
                 self_,
                 generics,
@@ -983,15 +960,14 @@ fn simplify_fn_type<'tcx, 'a>(
                 is_return,
                 cache,
             );
+            res.push(get_index_type(arg, ty_generics, rgen));
         }
-        res.push(get_index_type(arg, ty_generics, rgen));
-    } else if let Type::BareFunction(ref bf) = *arg {
-        let mut ty_generics = Vec::new();
-        for ty in bf.decl.inputs.values.iter().map(|arg| &arg.type_) {
+        Type::Array(ref ty, _) => {
+            let mut ty_generics = Vec::new();
             simplify_fn_type(
                 self_,
                 generics,
-                ty,
+                &ty,
                 tcx,
                 recurse + 1,
                 &mut ty_generics,
@@ -999,62 +975,11 @@ fn simplify_fn_type<'tcx, 'a>(
                 is_return,
                 cache,
             );
+            res.push(get_index_type(arg, ty_generics, rgen));
         }
-        // The search index, for simplicity's sake, represents fn pointers and closures
-        // the same way: as a tuple for the parameters, and an associated type for the
-        // return type.
-        let mut ty_output = Vec::new();
-        simplify_fn_type(
-            self_,
-            generics,
-            &bf.decl.output,
-            tcx,
-            recurse + 1,
-            &mut ty_output,
-            rgen,
-            is_return,
-            cache,
-        );
-        let ty_bindings = vec![(RenderTypeId::AssociatedType(sym::Output), ty_output)];
-        res.push(RenderType {
-            id: get_index_type_id(&arg, rgen),
-            bindings: Some(ty_bindings),
-            generics: Some(ty_generics),
-        });
-    } else if let Type::BorrowedRef { lifetime: _, mutability, ref type_ } = *arg {
-        let mut ty_generics = Vec::new();
-        if mutability.is_mut() {
-            ty_generics.push(RenderType {
-                id: Some(RenderTypeId::Mut),
-                generics: None,
-                bindings: None,
-            });
-        }
-        simplify_fn_type(
-            self_,
-            generics,
-            &type_,
-            tcx,
-            recurse + 1,
-            &mut ty_generics,
-            rgen,
-            is_return,
-            cache,
-        );
-        res.push(get_index_type(arg, ty_generics, rgen));
-    } else {
-        // This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're
-        // looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't.
-        //
-        // So in here, we can add it directly and look for its own type parameters (so for `Option`,
-        // we will look for them but not for `T`).
-        let mut ty_generics = Vec::new();
-        let mut ty_constraints = Vec::new();
-        if let Some(arg_generics) = arg.generic_args() {
-            for ty in arg_generics.into_iter().filter_map(|param| match param {
-                clean::GenericArg::Type(ty) => Some(ty),
-                _ => None,
-            }) {
+        Type::Tuple(ref tys) => {
+            let mut ty_generics = Vec::new();
+            for ty in tys {
                 simplify_fn_type(
                     self_,
                     generics,
@@ -1067,94 +992,181 @@ fn simplify_fn_type<'tcx, 'a>(
                     cache,
                 );
             }
-            for constraint in arg_generics.constraints() {
-                simplify_fn_constraint(
+            res.push(get_index_type(arg, ty_generics, rgen));
+        }
+        Type::BareFunction(ref bf) => {
+            let mut ty_generics = Vec::new();
+            for ty in bf.decl.inputs.values.iter().map(|arg| &arg.type_) {
+                simplify_fn_type(
                     self_,
                     generics,
-                    &constraint,
+                    ty,
                     tcx,
                     recurse + 1,
-                    &mut ty_constraints,
+                    &mut ty_generics,
                     rgen,
                     is_return,
                     cache,
                 );
             }
+            // The search index, for simplicity's sake, represents fn pointers and closures
+            // the same way: as a tuple for the parameters, and an associated type for the
+            // return type.
+            let mut ty_output = Vec::new();
+            simplify_fn_type(
+                self_,
+                generics,
+                &bf.decl.output,
+                tcx,
+                recurse + 1,
+                &mut ty_output,
+                rgen,
+                is_return,
+                cache,
+            );
+            let ty_bindings = vec![(RenderTypeId::AssociatedType(sym::Output), ty_output)];
+            res.push(RenderType {
+                id: get_index_type_id(&arg, rgen),
+                bindings: Some(ty_bindings),
+                generics: Some(ty_generics),
+            });
         }
-        // Every trait associated type on self gets assigned to a type parameter index
-        // this same one is used later for any appearances of these types
-        //
-        // for example, Iterator::next is:
-        //
-        //     trait Iterator {
-        //         fn next(&mut self) -> Option<Self::Item>
-        //     }
-        //
-        // Self is technically just Iterator, but we want to pretend it's more like this:
-        //
-        //     fn next<T>(self: Iterator<Item=T>) -> Option<T>
-        if is_self
-            && let Type::Path { path } = arg
-            && let def_id = path.def_id()
-            && let Some(trait_) = cache.traits.get(&def_id)
-            && trait_.items.iter().any(|at| at.is_ty_associated_type())
-        {
-            for assoc_ty in &trait_.items {
-                if let clean::ItemKind::TyAssocTypeItem(_generics, bounds) = &*assoc_ty.kind
-                    && let Some(name) = assoc_ty.name
-                {
-                    let idx = -isize::try_from(rgen.len() + 1).unwrap();
-                    let (idx, stored_bounds) = rgen
-                        .entry(SimplifiedParam::AssociatedType(def_id, name))
-                        .or_insert_with(|| (idx, Vec::new()));
-                    let idx = *idx;
-                    if stored_bounds.is_empty() {
-                        // Can't just pass stored_bounds to simplify_fn_type,
-                        // because it also accepts rgen as a parameter.
-                        // Instead, have it fill in this local, then copy it into the map afterward.
-                        let mut type_bounds = Vec::new();
-                        for bound in bounds {
-                            if let Some(path) = bound.get_trait_path() {
-                                let ty = Type::Path { path };
-                                simplify_fn_type(
-                                    self_,
-                                    generics,
-                                    &ty,
-                                    tcx,
-                                    recurse + 1,
-                                    &mut type_bounds,
-                                    rgen,
-                                    is_return,
-                                    cache,
-                                );
-                            }
-                        }
-                        let stored_bounds = &mut rgen
-                            .get_mut(&SimplifiedParam::AssociatedType(def_id, name))
-                            .unwrap()
-                            .1;
+        Type::BorrowedRef { lifetime: _, mutability, ref type_ } => {
+            let mut ty_generics = Vec::new();
+            if mutability.is_mut() {
+                ty_generics.push(RenderType {
+                    id: Some(RenderTypeId::Mut),
+                    generics: None,
+                    bindings: None,
+                });
+            }
+            simplify_fn_type(
+                self_,
+                generics,
+                &type_,
+                tcx,
+                recurse + 1,
+                &mut ty_generics,
+                rgen,
+                is_return,
+                cache,
+            );
+            res.push(get_index_type(arg, ty_generics, rgen));
+        }
+        _ => {
+            // This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're
+            // looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't.
+            //
+            // So in here, we can add it directly and look for its own type parameters (so for `Option`,
+            // we will look for them but not for `T`).
+            let mut ty_generics = Vec::new();
+            let mut ty_constraints = Vec::new();
+            if let Some(arg_generics) = arg.generic_args() {
+                for ty in arg_generics.into_iter().filter_map(|param| match param {
+                    clean::GenericArg::Type(ty) => Some(ty),
+                    _ => None,
+                }) {
+                    simplify_fn_type(
+                        self_,
+                        generics,
+                        &ty,
+                        tcx,
+                        recurse + 1,
+                        &mut ty_generics,
+                        rgen,
+                        is_return,
+                        cache,
+                    );
+                }
+                for constraint in arg_generics.constraints() {
+                    simplify_fn_constraint(
+                        self_,
+                        generics,
+                        &constraint,
+                        tcx,
+                        recurse + 1,
+                        &mut ty_constraints,
+                        rgen,
+                        is_return,
+                        cache,
+                    );
+                }
+            }
+            // Every trait associated type on self gets assigned to a type parameter index
+            // this same one is used later for any appearances of these types
+            //
+            // for example, Iterator::next is:
+            //
+            //     trait Iterator {
+            //         fn next(&mut self) -> Option<Self::Item>
+            //     }
+            //
+            // Self is technically just Iterator, but we want to pretend it's more like this:
+            //
+            //     fn next<T>(self: Iterator<Item=T>) -> Option<T>
+            if is_self
+                && let Type::Path { path } = arg
+                && let def_id = path.def_id()
+                && let Some(trait_) = cache.traits.get(&def_id)
+                && trait_.items.iter().any(|at| at.is_ty_associated_type())
+            {
+                for assoc_ty in &trait_.items {
+                    if let clean::ItemKind::TyAssocTypeItem(_generics, bounds) = &*assoc_ty.kind
+                        && let Some(name) = assoc_ty.name
+                    {
+                        let idx = -isize::try_from(rgen.len() + 1).unwrap();
+                        let (idx, stored_bounds) = rgen
+                            .entry(SimplifiedParam::AssociatedType(def_id, name))
+                            .or_insert_with(|| (idx, Vec::new()));
+                        let idx = *idx;
                         if stored_bounds.is_empty() {
-                            *stored_bounds = type_bounds;
+                            // Can't just pass stored_bounds to simplify_fn_type,
+                            // because it also accepts rgen as a parameter.
+                            // Instead, have it fill in this local, then copy it into the map afterward.
+                            let mut type_bounds = Vec::new();
+                            for bound in bounds {
+                                if let Some(path) = bound.get_trait_path() {
+                                    let ty = Type::Path { path };
+                                    simplify_fn_type(
+                                        self_,
+                                        generics,
+                                        &ty,
+                                        tcx,
+                                        recurse + 1,
+                                        &mut type_bounds,
+                                        rgen,
+                                        is_return,
+                                        cache,
+                                    );
+                                }
+                            }
+                            let stored_bounds = &mut rgen
+                                .get_mut(&SimplifiedParam::AssociatedType(def_id, name))
+                                .unwrap()
+                                .1;
+                            if stored_bounds.is_empty() {
+                                *stored_bounds = type_bounds;
+                            }
                         }
+                        ty_constraints.push((
+                            RenderTypeId::AssociatedType(name),
+                            vec![RenderType {
+                                id: Some(RenderTypeId::Index(idx)),
+                                generics: None,
+                                bindings: None,
+                            }],
+                        ))
                     }
-                    ty_constraints.push((
-                        RenderTypeId::AssociatedType(name),
-                        vec![RenderType {
-                            id: Some(RenderTypeId::Index(idx)),
-                            generics: None,
-                            bindings: None,
-                        }],
-                    ))
                 }
             }
-        }
-        let id = get_index_type_id(&arg, rgen);
-        if id.is_some() || !ty_generics.is_empty() {
-            res.push(RenderType {
-                id,
-                bindings: if ty_constraints.is_empty() { None } else { Some(ty_constraints) },
-                generics: if ty_generics.is_empty() { None } else { Some(ty_generics) },
-            });
+            let id = get_index_type_id(&arg, rgen);
+            if id.is_some() || !ty_generics.is_empty() {
+                res.push(RenderType {
+                    id,
+                    bindings: if ty_constraints.is_empty() { None } else { Some(ty_constraints) },
+                    generics: if ty_generics.is_empty() { None } else { Some(ty_generics) },
+                });
+            }
         }
     }
 }
diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs
index e5bc2ace203..101cc839f09 100644
--- a/src/librustdoc/html/render/sidebar.rs
+++ b/src/librustdoc/html/render/sidebar.rs
@@ -1,17 +1,18 @@
-use std::{borrow::Cow, rc::Rc};
+use std::borrow::Cow;
+use std::rc::Rc;
 
 use rinja::Template;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_hir::{def::CtorKind, def_id::DefIdSet};
+use rustc_hir::def::CtorKind;
+use rustc_hir::def_id::DefIdSet;
 use rustc_middle::ty::{self, TyCtxt};
 
-use crate::{
-    clean,
-    formats::{item_type::ItemType, Impl},
-    html::{format::Buffer, markdown::IdMap},
-};
-
 use super::{item_ty_to_section, Context, ItemSection};
+use crate::clean;
+use crate::formats::item_type::ItemType;
+use crate::formats::Impl;
+use crate::html::format::Buffer;
+use crate::html::markdown::IdMap;
 
 #[derive(Template)]
 #[template(path = "sidebar.html")]
@@ -76,6 +77,22 @@ impl<'a> Link<'a> {
     }
 }
 
+pub(crate) mod filters {
+    use std::fmt::Display;
+
+    use rinja::filters::Safe;
+
+    use crate::html::escape::EscapeBodyTextWithWbr;
+    use crate::html::render::display_fn;
+    pub(crate) fn wrapped<T>(v: T) -> rinja::Result<Safe<impl Display>>
+    where
+        T: Display,
+    {
+        let string = v.to_string();
+        Ok(Safe(display_fn(move |f| EscapeBodyTextWithWbr(&string).fmt(f))))
+    }
+}
+
 pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
     let blocks: Vec<LinkBlock<'_>> = match *it.kind {
         clean::StructItem(ref s) => sidebar_struct(cx, it, s),
diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs
index 0535246ae10..5b53277c059 100644
--- a/src/librustdoc/html/render/span_map.rs
+++ b/src/librustdoc/html/render/span_map.rs
@@ -1,5 +1,4 @@
-use crate::clean::{self, rustc_span, PrimitiveType};
-use crate::html::sources;
+use std::path::{Path, PathBuf};
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::{DefKind, Res};
@@ -11,7 +10,8 @@ use rustc_middle::ty::TyCtxt;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::{BytePos, ExpnKind, Span};
 
-use std::path::{Path, PathBuf};
+use crate::clean::{self, rustc_span, PrimitiveType};
+use crate::html::sources;
 
 /// This enum allows us to store two different kinds of information:
 ///
diff --git a/src/librustdoc/html/render/type_layout.rs b/src/librustdoc/html/render/type_layout.rs
index 35a38d5375f..cd4e597ff28 100644
--- a/src/librustdoc/html/render/type_layout.rs
+++ b/src/librustdoc/html/render/type_layout.rs
@@ -1,14 +1,14 @@
-use rinja::Template;
+use std::fmt;
 
+use rinja::Template;
 use rustc_data_structures::captures::Captures;
 use rustc_hir::def_id::DefId;
 use rustc_middle::span_bug;
-use rustc_middle::ty::{self, layout::LayoutError};
+use rustc_middle::ty::layout::LayoutError;
+use rustc_middle::ty::{self};
 use rustc_span::symbol::Symbol;
 use rustc_target::abi::{Primitive, TagEncoding, Variants};
 
-use std::fmt;
-
 use crate::html::format::display_fn;
 use crate::html::render::Context;
 
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index 7b4d1fa5305..22f115f92cc 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -1,12 +1,9 @@
-use crate::clean;
-use crate::clean::utils::has_doc_flag;
-use crate::docfs::PathError;
-use crate::error::Error;
-use crate::html::format;
-use crate::html::highlight;
-use crate::html::layout;
-use crate::html::render::Context;
-use crate::visit::DocVisitor;
+use std::cell::RefCell;
+use std::ffi::OsStr;
+use std::ops::RangeInclusive;
+use std::path::{Component, Path, PathBuf};
+use std::rc::Rc;
+use std::{fmt, fs};
 
 use rinja::Template;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -15,13 +12,13 @@ use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_span::{sym, FileName};
 
-use std::cell::RefCell;
-use std::ffi::OsStr;
-use std::fmt;
-use std::fs;
-use std::ops::RangeInclusive;
-use std::path::{Component, Path, PathBuf};
-use std::rc::Rc;
+use crate::clean;
+use crate::clean::utils::has_doc_flag;
+use crate::docfs::PathError;
+use crate::error::Error;
+use crate::html::render::Context;
+use crate::html::{format, highlight, layout};
+use crate::visit::DocVisitor;
 
 pub(crate) fn render(cx: &mut Context<'_>, krate: &clean::Crate) -> Result<(), Error> {
     info!("emitting source files");
diff --git a/src/librustdoc/html/static/css/noscript.css b/src/librustdoc/html/static/css/noscript.css
index 6e10cf21537..86e8edad703 100644
--- a/src/librustdoc/html/static/css/noscript.css
+++ b/src/librustdoc/html/static/css/noscript.css
@@ -104,10 +104,6 @@ nav.sub {
 	--code-highlight-doc-comment-color: #4d4d4c;
 	--src-line-numbers-span-color: #c67e2d;
 	--src-line-number-highlighted-background-color: #fdffd3;
-	--test-arrow-color: #f5f5f5;
-	--test-arrow-background-color: rgba(78, 139, 202, 0.2);
-	--test-arrow-hover-color: #f5f5f5;
-	--test-arrow-hover-background-color: rgb(78, 139, 202);
 	--target-background-color: #fdffd3;
 	--target-border-color: #ad7c37;
 	--kbd-color: #000;
@@ -210,10 +206,6 @@ nav.sub {
 		--code-highlight-doc-comment-color: #8ca375;
 		--src-line-numbers-span-color: #3b91e2;
 		--src-line-number-highlighted-background-color: #0a042f;
-		--test-arrow-color: #dedede;
-		--test-arrow-background-color: rgba(78, 139, 202, 0.2);
-		--test-arrow-hover-color: #dedede;
-		--test-arrow-hover-background-color: #4e8bca;
 		--target-background-color: #494a3d;
 		--target-border-color: #bb7410;
 		--kbd-color: #000;
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 41c506f33dc..eb5a5d935e2 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -16,6 +16,24 @@
 	--src-sidebar-width: 300px;
 	--desktop-sidebar-z-index: 100;
 	--sidebar-elems-left-padding: 24px;
+	/* clipboard <https://github.com/rust-lang/crates.io/commits/main/public/assets/copy.svg> */
+	--clipboard-image: url('data:image/svg+xml,<svg width="19" height="18" viewBox="0 0 24 25" \
+xmlns="http://www.w3.org/2000/svg" aria-label="Copy to clipboard">\
+<path d="M18 20h2v3c0 1-1 2-2 2H2c-.998 0-2-1-2-2V5c0-.911.755-1.667 1.667-1.667h5A3.323 3.323 0 \
+0110 0a3.323 3.323 0 013.333 3.333h5C19.245 3.333 20 4.09 20 5v8.333h-2V9H2v14h16v-3zM3 \
+7h14c0-.911-.793-1.667-1.75-1.667H13.5c-.957 0-1.75-.755-1.75-1.666C11.75 2.755 10.957 2 10 \
+2s-1.75.755-1.75 1.667c0 .911-.793 1.666-1.75 1.666H4.75C3.793 5.333 3 6.09 3 7z"/>\
+<path d="M4 19h6v2H4zM12 11H4v2h8zM4 17h4v-2H4zM15 15v-3l-4.5 4.5L15 21v-3l8.027-.032L23 15z"/>\
+</svg>');
+	--copy-path-height: 34px;
+	--copy-path-width: 33px;
+	/* Checkmark <https://www.svgrepo.com/svg/335033/checkmark> */
+	--checkmark-image: url('data:image/svg+xml,<svg viewBox="-1 -1 23 23" \
+xmlns="http://www.w3.org/2000/svg" fill="black" height="18px">\
+<g><path d="M9 19.414l-6.707-6.707 1.414-1.414L9 16.586 20.293 5.293l1.414 1.414"></path>\
+</g></svg>');
+	--button-left-margin: 4px;
+	--button-border-radius: 2px;
 }
 
 /* See FiraSans-LICENSE.txt for the Fira Sans license. */
@@ -335,7 +353,7 @@ details:not(.toggle) summary {
 	margin-bottom: .6em;
 }
 
-code, pre, a.test-arrow, .code-header {
+code, pre, .code-header {
 	font-family: "Source Code Pro", monospace;
 }
 .docblock code, .docblock-short code {
@@ -568,12 +586,15 @@ ul.block, .block li {
 }
 
 .sidebar h2 {
+	text-wrap: balance;
 	overflow-wrap: anywhere;
 	padding: 0;
 	margin: 0.7rem 0;
 }
 
 .sidebar h3 {
+	text-wrap: balance;
+	overflow-wrap: anywhere;
 	font-size: 1.125rem; /* 18px */
 	padding: 0;
 	margin: 0;
@@ -723,6 +744,11 @@ ul.block, .block li {
 	position: relative;
 	margin-bottom: 10px;
 }
+
+.rustdoc .example-wrap > pre {
+	border-radius: 6px;
+}
+
 /* For the last child of a div, the margin will be taken care of
 	by the margin-top of the next item. */
 .rustdoc .example-wrap:last-child {
@@ -904,7 +930,7 @@ a.doc-anchor {
 	left: -17px;
 	/* We add this padding so that when the cursor moves from the heading's text to the anchor,
 	   the anchor doesn't disappear. */
-	padding-right: 5px;
+	padding-right: 10px;
 	/* And this padding is used to make the anchor larger and easier to click on. */
 	padding-left: 3px;
 }
@@ -920,8 +946,8 @@ because of the `[-]` element which would overlap with it. */
 .main-heading a:hover,
 .example-wrap .rust a:hover,
 .all-items a:hover,
-.docblock a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover:not(.doc-anchor),
-.docblock-short a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover,
+.docblock a:not(.scrape-help):not(.tooltip):hover:not(.doc-anchor),
+.docblock-short a:not(.scrape-help):not(.tooltip):hover,
 .item-info a {
 	text-decoration: underline;
 }
@@ -1427,25 +1453,68 @@ documentation. */
 	top: 20px;
 }
 
-a.test-arrow {
+.example-wrap > a.test-arrow, .example-wrap .button-holder {
 	visibility: hidden;
 	position: absolute;
-	padding: 5px 10px 5px 10px;
-	border-radius: 5px;
-	font-size: 1.375rem;
-	top: 5px;
-	right: 5px;
+	top: 4px;
+	right: 4px;
 	z-index: 1;
-	color: var(--test-arrow-color);
-	background-color: var(--test-arrow-background-color);
 }
-a.test-arrow:hover {
-	color: var(--test-arrow-hover-color);
-	background-color: var(--test-arrow-hover-background-color);
+a.test-arrow {
+	height: var(--copy-path-height);
+	padding: 6px 4px 0 11px;
+}
+a.test-arrow::before {
+	content: url('data:image/svg+xml,<svg viewBox="0 0 20 20" width="18" height="20" \
+		xmlns="http://www.w3.org/2000/svg"><path d="M0 0l18 10-18 10z"/></svg>');
+}
+.example-wrap .button-holder {
+	display: flex;
+}
+
+/*
+On iPad, the ":hover" state sticks around, making things work not greatly. Do work around
+it, we move it into this media query. More information can be found at:
+https://css-tricks.com/solving-sticky-hover-states-with-media-hover-hover/
+
+However, using `@media (hover: hover)` makes this rule never to be applied in GUI tests, so
+instead, we check that it's not a "finger" cursor.
+*/
+@media not (pointer: coarse) {
+	.example-wrap:hover > a.test-arrow, .example-wrap:hover > .button-holder {
+		visibility: visible;
+	}
 }
-.example-wrap:hover .test-arrow {
+.example-wrap .button-holder.keep-visible {
 	visibility: visible;
 }
+.example-wrap .button-holder .copy-button, .example-wrap .test-arrow {
+	background: var(--main-background-color);
+	cursor: pointer;
+	border-radius: var(--button-border-radius);
+	height: var(--copy-path-height);
+	width: var(--copy-path-width);
+}
+.example-wrap .button-holder .copy-button {
+	margin-left: var(--button-left-margin);
+	padding: 2px 0 0 4px;
+	border: 0;
+}
+.example-wrap .button-holder .copy-button::before,
+.example-wrap .test-arrow::before {
+	filter: var(--copy-path-img-filter);
+}
+.example-wrap .button-holder .copy-button::before {
+	content: var(--clipboard-image);
+}
+.example-wrap .button-holder .copy-button:hover::before,
+.example-wrap .test-arrow:hover::before {
+	filter: var(--copy-path-img-hover-filter);
+}
+.example-wrap .button-holder .copy-button.clicked::before {
+	content: var(--checkmark-image);
+	padding-right: 5px;
+}
 
 .code-attribute {
 	font-weight: 300;
@@ -1610,7 +1679,7 @@ a.tooltip:hover::after {
 }
 
 #settings-menu, #help-button {
-	margin-left: 4px;
+	margin-left: var(--button-left-margin);
 	display: flex;
 }
 #sidebar-button {
@@ -1641,7 +1710,7 @@ a.tooltip:hover::after {
 	justify-content: center;
 	background-color: var(--button-background-color);
 	border: 1px solid var(--border-color);
-	border-radius: 2px;
+	border-radius: var(--button-border-radius);
 	color: var(--settings-button-color);
 	/* Rare exception to specifying font sizes in rem. Since this is acting
 	   as an icon, it's okay to specify their sizes in pixels. */
@@ -1693,8 +1762,8 @@ a.tooltip:hover::after {
 #copy-path {
 	color: var(--copy-path-button-color);
 	background: var(--main-background-color);
-	height: 34px;
-	width: 33px;
+	height: var(--copy-path-height);
+	width: var(--copy-path-width);
 	margin-left: 10px;
 	padding: 0;
 	padding-left: 2px;
@@ -1703,27 +1772,13 @@ a.tooltip:hover::after {
 }
 #copy-path::before {
 	filter: var(--copy-path-img-filter);
-	/* clipboard <https://github.com/rust-lang/crates.io/commits/main/public/assets/copy.svg> */
-	content: url('data:image/svg+xml,<svg width="19" height="18" viewBox="0 0 24 25" \
-xmlns="http://www.w3.org/2000/svg" aria-label="Copy to clipboard">\
-<path d="M18 20h2v3c0 1-1 2-2 2H2c-.998 0-2-1-2-2V5c0-.911.755-1.667 1.667-1.667h5A3.323 3.323 0 \
-0110 0a3.323 3.323 0 013.333 3.333h5C19.245 3.333 20 4.09 20 5v8.333h-2V9H2v14h16v-3zM3 \
-7h14c0-.911-.793-1.667-1.75-1.667H13.5c-.957 0-1.75-.755-1.75-1.666C11.75 2.755 10.957 2 10 \
-2s-1.75.755-1.75 1.667c0 .911-.793 1.666-1.75 1.666H4.75C3.793 5.333 3 6.09 3 7z"/>\
-<path d="M4 19h6v2H4zM12 11H4v2h8zM4 17h4v-2H4zM15 15v-3l-4.5 4.5L15 21v-3l8.027-.032L23 15z"/>\
-</svg>');
-	width: 19px;
-	height: 18px;
+	content: var(--clipboard-image);
 }
 #copy-path:hover::before {
 	filter: var(--copy-path-img-hover-filter);
 }
 #copy-path.clicked::before {
-	/* Checkmark <https://www.svgrepo.com/svg/335033/checkmark> */
-	content: url('data:image/svg+xml,<svg viewBox="-1 -1 23 23" xmlns="http://www.w3.org/2000/svg" \
-		fill="black" height="18px">\
-		<g><path d="M9 19.414l-6.707-6.707 1.414-1.414L9 16.586 20.293 5.293l1.414 1.414"></path>\
-		</g></svg>');
+	content: var(--checkmark-image);
 }
 
 @keyframes rotating {
@@ -2183,7 +2238,7 @@ in src-script.js and main.js
 		width: 33%;
 	}
 	.item-table > li > div {
-		word-break: break-all;
+		overflow-wrap: anywhere;
 	}
 }
 
@@ -2497,10 +2552,6 @@ by default.
 	--code-highlight-doc-comment-color: #4d4d4c;
 	--src-line-numbers-span-color: #c67e2d;
 	--src-line-number-highlighted-background-color: #fdffd3;
-	--test-arrow-color: #f5f5f5;
-	--test-arrow-background-color: rgba(78, 139, 202, 0.2);
-	--test-arrow-hover-color: #f5f5f5;
-	--test-arrow-hover-background-color: rgb(78, 139, 202);
 	--target-background-color: #fdffd3;
 	--target-border-color: #ad7c37;
 	--kbd-color: #000;
@@ -2603,10 +2654,6 @@ by default.
 	--code-highlight-doc-comment-color: #8ca375;
 	--src-line-numbers-span-color: #3b91e2;
 	--src-line-number-highlighted-background-color: #0a042f;
-	--test-arrow-color: #dedede;
-	--test-arrow-background-color: rgba(78, 139, 202, 0.2);
-	--test-arrow-hover-color: #dedede;
-	--test-arrow-hover-background-color: #4e8bca;
 	--target-background-color: #494a3d;
 	--target-border-color: #bb7410;
 	--kbd-color: #000;
@@ -2716,10 +2763,6 @@ Original by Dempfi (https://github.com/dempfi/ayu)
 	--code-highlight-doc-comment-color: #a1ac88;
 	--src-line-numbers-span-color: #5c6773;
 	--src-line-number-highlighted-background-color: rgba(255, 236, 164, 0.06);
-	--test-arrow-color: #788797;
-	--test-arrow-background-color: rgba(57, 175, 215, 0.09);
-	--test-arrow-hover-color: #c5c5c5;
-	--test-arrow-hover-background-color: rgba(57, 175, 215, 0.368);
 	--target-background-color: rgba(255, 236, 164, 0.06);
 	--target-border-color: rgba(255, 180, 76, 0.85);
 	--kbd-color: #c5c5c5;
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 9506bc9ed22..75f2a1418cd 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -390,13 +390,18 @@ function preLoadCss(cssUrl) {
             if (splitAt !== -1) {
                 const implId = savedHash.slice(0, splitAt);
                 const assocId = savedHash.slice(splitAt + 1);
-                const implElem = document.getElementById(implId);
-                if (implElem && implElem.parentElement.tagName === "SUMMARY" &&
-                    implElem.parentElement.parentElement.tagName === "DETAILS") {
-                    onEachLazy(implElem.parentElement.parentElement.querySelectorAll(
+                const implElems = document.querySelectorAll(
+                    `details > summary > section[id^="${implId}"]`,
+                );
+                onEachLazy(implElems, implElem => {
+                    const numbered = /^(.+?)-([0-9]+)$/.exec(implElem.id);
+                    if (implElem.id !== implId && (!numbered || numbered[1] !== implId)) {
+                        return false;
+                    }
+                    return onEachLazy(implElem.parentElement.parentElement.querySelectorAll(
                         `[id^="${assocId}"]`),
                         item => {
-                            const numbered = /([^-]+)-([0-9]+)/.exec(item.id);
+                            const numbered = /^(.+?)-([0-9]+)$/.exec(item.id);
                             if (item.id === assocId || (numbered && numbered[1] === assocId)) {
                                 openParentDetails(item);
                                 item.scrollIntoView();
@@ -404,10 +409,11 @@ function preLoadCss(cssUrl) {
                                 setTimeout(() => {
                                     window.location.replace("#" + item.id);
                                 }, 0);
+                                return true;
                             }
                         },
                     );
-                }
+                });
             }
         }
     }
@@ -568,7 +574,6 @@ function preLoadCss(cssUrl) {
             //block("associatedconstant", "associated-consts", "Associated Constants");
             block("foreigntype", "foreign-types", "Foreign Types");
             block("keyword", "keywords", "Keywords");
-            block("opaque", "opaque-types", "Opaque Types");
             block("attr", "attributes", "Attribute Macros");
             block("derive", "derives", "Derive Macros");
             block("traitalias", "trait-aliases", "Trait Aliases");
@@ -1115,8 +1120,7 @@ function preLoadCss(cssUrl) {
         wrapper.style.left = 0;
         wrapper.style.right = "auto";
         wrapper.style.visibility = "hidden";
-        const body = document.getElementsByTagName("body")[0];
-        body.appendChild(wrapper);
+        document.body.appendChild(wrapper);
         const wrapperPos = wrapper.getBoundingClientRect();
         // offset so that the arrow points at the center of the "(i)"
         const finalPos = pos.left + window.scrollX - wrapperPos.width + 24;
@@ -1235,8 +1239,7 @@ function preLoadCss(cssUrl) {
                 }
                 window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE = false;
             }
-            const body = document.getElementsByTagName("body")[0];
-            body.removeChild(window.CURRENT_TOOLTIP_ELEMENT);
+            document.body.removeChild(window.CURRENT_TOOLTIP_ELEMENT);
             clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT);
             window.CURRENT_TOOLTIP_ELEMENT = null;
         }
@@ -1771,9 +1774,37 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
 }());
 
 // This section handles the copy button that appears next to the path breadcrumbs
+// and the copy buttons on the code examples.
 (function() {
-    let reset_button_timeout = null;
+    // Common functions to copy buttons.
+    function copyContentToClipboard(content) {
+        const el = document.createElement("textarea");
+        el.value = content;
+        el.setAttribute("readonly", "");
+        // To not make it appear on the screen.
+        el.style.position = "absolute";
+        el.style.left = "-9999px";
+
+        document.body.appendChild(el);
+        el.select();
+        document.execCommand("copy");
+        document.body.removeChild(el);
+    }
+
+    function copyButtonAnimation(button) {
+        button.classList.add("clicked");
+
+        if (button.reset_button_timeout !== undefined) {
+            window.clearTimeout(button.reset_button_timeout);
+        }
 
+        button.reset_button_timeout = window.setTimeout(() => {
+            button.reset_button_timeout = undefined;
+            button.classList.remove("clicked");
+        }, 1000);
+    }
+
+    // Copy button that appears next to the path breadcrumbs.
     const but = document.getElementById("copy-path");
     if (!but) {
         return;
@@ -1788,29 +1819,74 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
             }
         });
 
-        const el = document.createElement("textarea");
-        el.value = path.join("::");
-        el.setAttribute("readonly", "");
-        // To not make it appear on the screen.
-        el.style.position = "absolute";
-        el.style.left = "-9999px";
+        copyContentToClipboard(path.join("::"));
+        copyButtonAnimation(but);
+    };
 
-        document.body.appendChild(el);
-        el.select();
-        document.execCommand("copy");
-        document.body.removeChild(el);
+    // Copy buttons on code examples.
+    function copyCode(codeElem) {
+        if (!codeElem) {
+            // Should never happen, but the world is a dark and dangerous place.
+            return;
+        }
+        copyContentToClipboard(codeElem.textContent);
+    }
 
-        but.classList.add("clicked");
+    function getExampleWrap(event) {
+        let elem = event.target;
+        while (!hasClass(elem, "example-wrap")) {
+            if (elem === document.body ||
+                elem.tagName === "A" ||
+                elem.tagName === "BUTTON" ||
+                hasClass(elem, "docblock")
+            ) {
+                return null;
+            }
+            elem = elem.parentElement;
+        }
+        return elem;
+    }
 
-        if (reset_button_timeout !== null) {
-            window.clearTimeout(reset_button_timeout);
+    function addCopyButton(event) {
+        const elem = getExampleWrap(event);
+        if (elem === null) {
+            return;
+        }
+        // Since the button will be added, no need to keep this listener around.
+        elem.removeEventListener("mouseover", addCopyButton);
+
+        const parent = document.createElement("div");
+        parent.className = "button-holder";
+        const runButton = elem.querySelector(".test-arrow");
+        if (runButton !== null) {
+            // If there is a run button, we move it into the same div.
+            parent.appendChild(runButton);
         }
+        elem.appendChild(parent);
+        const copyButton = document.createElement("button");
+        copyButton.className = "copy-button";
+        copyButton.title = "Copy code to clipboard";
+        copyButton.addEventListener("click", () => {
+            copyCode(elem.querySelector("pre > code"));
+            copyButtonAnimation(copyButton);
+        });
+        parent.appendChild(copyButton);
+    }
 
-        function reset_button() {
-            reset_button_timeout = null;
-            but.classList.remove("clicked");
+    function showHideCodeExampleButtons(event) {
+        const elem = getExampleWrap(event);
+        if (elem === null) {
+            return;
         }
+        const buttons = elem.querySelector(".button-holder");
+        if (buttons === null) {
+            return;
+        }
+        buttons.classList.toggle("keep-visible");
+    }
 
-        reset_button_timeout = window.setTimeout(reset_button, 1000);
-    };
+    onEachLazy(document.querySelectorAll(".docblock .example-wrap"), elem => {
+        elem.addEventListener("mouseover", addCopyButton);
+        elem.addEventListener("click", showHideCodeExampleButtons);
+    });
 }());
diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs
index 035376bace9..6157598ba38 100644
--- a/src/librustdoc/html/static_files.rs
+++ b/src/librustdoc/html/static_files.rs
@@ -3,11 +3,12 @@
 //! All the static files are included here for centralized access in case anything other than the
 //! HTML rendering code (say, the theme checker) needs to access one of these files.
 
-use rustc_data_structures::fx::FxHasher;
 use std::hash::Hasher;
 use std::path::{Path, PathBuf};
 use std::{fmt, str};
 
+use rustc_data_structures::fx::FxHasher;
+
 pub(crate) struct StaticFile {
     pub(crate) filename: PathBuf,
     pub(crate) bytes: &'static [u8],
diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
index cdf01fa7a97..65c4304e202 100644
--- a/src/librustdoc/html/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -98,7 +98,7 @@
             </a> {# #}
             {% endif %}
             <h2> {# #}
-                <a href="{{page.root_path|safe}}{{display_krate_with_trailing_slash|safe}}index.html">{{display_krate}}</a> {# #}
+                <a href="{{page.root_path|safe}}{{display_krate_with_trailing_slash|safe}}index.html">{{display_krate|wrapped|safe}}</a> {# #}
                 {% if !display_krate_version_number.is_empty() %}
                     <span class="version">{{+ display_krate_version_number}}</span>
                 {% endif %}
diff --git a/src/librustdoc/html/templates/sidebar.html b/src/librustdoc/html/templates/sidebar.html
index 3251b4c14c9..0990c2716b8 100644
--- a/src/librustdoc/html/templates/sidebar.html
+++ b/src/librustdoc/html/templates/sidebar.html
@@ -1,6 +1,6 @@
 {% if !title.is_empty() %}
     <h2 class="location"> {# #}
-        <a href="#">{{title_prefix}}{{title}}</a> {# #}
+        <a href="#">{{title_prefix}}{{title|wrapped|safe}}</a> {# #}
     </h2>
 {% endif %}
 <div class="sidebar-elems">
@@ -15,7 +15,9 @@
             {% for block in blocks %}
                 {% if block.should_render() %}
                     {% if !block.heading.name.is_empty() %}
-                        <h3><a href="#{{block.heading.href|safe}}">{{block.heading.name}}</a></h3>
+                        <h3><a href="#{{block.heading.href|safe}}"> {# #}
+                            {{block.heading.name|wrapped|safe}} {# #}
+                        </a></h3> {# #}
                     {% endif %}
                     {% if !block.links.is_empty() %}
                         <ul class="block{% if !block.class.is_empty() +%} {{+block.class}}{% endif %}">
@@ -29,6 +31,6 @@
         </section>
     {% endif %}
     {% if !path.is_empty() %}
-        <h2><a href="{% if is_mod %}../{% endif %}index.html">In {{+ path}}</a></h2>
+        <h2><a href="{% if is_mod %}../{% endif %}index.html">In {{+ path|wrapped|safe}}</a></h2>
     {% endif %}
 </div>
diff --git a/src/librustdoc/html/tests.rs b/src/librustdoc/html/tests.rs
index 437d3995e29..059f99c0c9e 100644
--- a/src/librustdoc/html/tests.rs
+++ b/src/librustdoc/html/tests.rs
@@ -1,6 +1,7 @@
-use crate::html::format::href_relative_parts;
 use rustc_span::{sym, Symbol};
 
+use crate::html::format::href_relative_parts;
+
 fn assert_relative_path(expected: &[Symbol], relative_to_fqp: &[Symbol], fqp: &[Symbol]) {
     // No `create_default_session_globals_then` call is needed here because all
     // the symbols used are static, and no `Symbol::intern` calls occur.
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 4ab0df36708..b97d710c007 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -8,14 +8,14 @@ use std::fmt;
 
 use rustc_ast::ast;
 use rustc_attr::DeprecatedSince;
-use rustc_hir::{def::CtorKind, def::DefKind, def_id::DefId};
+use rustc_hir::def::{CtorKind, DefKind};
+use rustc_hir::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};
 use rustc_target::spec::abi::Abi as RustcAbi;
-
 use rustdoc_json_types::*;
 
 use crate::clean::{self, ItemId};
@@ -188,6 +188,16 @@ impl FromWithTcx<clean::Constant> for Constant {
     }
 }
 
+impl FromWithTcx<clean::ConstantKind> for Constant {
+    // FIXME(generic_const_items): Add support for generic const items.
+    fn from_tcx(constant: clean::ConstantKind, tcx: TyCtxt<'_>) -> Self {
+        let expr = constant.expr(tcx);
+        let value = constant.value(tcx);
+        let is_literal = constant.is_literal(tcx);
+        Constant { expr, value, is_literal }
+    }
+}
+
 impl FromWithTcx<clean::AssocItemConstraint> for TypeBinding {
     fn from_tcx(constraint: clean::AssocItemConstraint, tcx: TyCtxt<'_>) -> Self {
         TypeBinding {
@@ -323,10 +333,9 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
         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)),
         // FIXME(generic_const_items): Add support for generic free consts
-        ConstantItem(_generics, t, c) => {
-            ItemEnum::Constant { type_: (*t).into_tcx(tcx), const_: c.into_tcx(tcx) }
+        ConstantItem(ci) => {
+            ItemEnum::Constant { type_: ci.type_.into_tcx(tcx), const_: ci.kind.into_tcx(tcx) }
         }
         MacroItem(m) => ItemEnum::Macro(m.source),
         ProcMacroItem(m) => ItemEnum::ProcMacro(m.into_tcx(tcx)),
@@ -341,8 +350,8 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
             ItemEnum::AssocConst { type_: (*ty).into_tcx(tcx), default: None }
         }
         // FIXME(generic_const_items): Add support for generic associated consts.
-        AssocConstItem(_generics, ty, default) => {
-            ItemEnum::AssocConst { type_: (*ty).into_tcx(tcx), default: Some(default.expr(tcx)) }
+        AssocConstItem(ci) => {
+            ItemEnum::AssocConst { type_: ci.type_.into_tcx(tcx), default: Some(ci.kind.expr(tcx)) }
         }
         TyAssocTypeItem(g, b) => ItemEnum::AssocType {
             generics: g.into_tcx(tcx),
@@ -569,7 +578,7 @@ impl FromWithTcx<clean::Type> for Type {
     fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
         use clean::Type::{
             Array, BareFunction, BorrowedRef, Generic, ImplTrait, Infer, Primitive, QPath,
-            RawPointer, Slice, Tuple,
+            RawPointer, SelfTy, Slice, Tuple,
         };
 
         match ty {
@@ -579,6 +588,8 @@ impl FromWithTcx<clean::Type> for Type {
                 traits: bounds.into_tcx(tcx),
             }),
             Generic(s) => Type::Generic(s.to_string()),
+            // FIXME: add dedicated variant to json Type?
+            SelfTy => Type::Generic("Self".to_owned()),
             Primitive(p) => Type::Primitive(p.as_sym().to_string()),
             BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_tcx(tcx))),
             Tuple(t) => Type::Tuple(t.into_tcx(tcx)),
@@ -820,16 +831,10 @@ impl FromWithTcx<Box<clean::TypeAlias>> for TypeAlias {
     }
 }
 
-impl FromWithTcx<clean::OpaqueTy> for OpaqueTy {
-    fn from_tcx(opaque: clean::OpaqueTy, tcx: TyCtxt<'_>) -> Self {
-        OpaqueTy { bounds: opaque.bounds.into_tcx(tcx), generics: opaque.generics.into_tcx(tcx) }
-    }
-}
-
 impl FromWithTcx<clean::Static> for Static {
     fn from_tcx(stat: clean::Static, tcx: TyCtxt<'_>) -> Self {
         Static {
-            type_: stat.type_.into_tcx(tcx),
+            type_: (*stat.type_).into_tcx(tcx),
             mutable: stat.mutability == ast::Mutability::Mut,
             expr: stat
                 .expr
@@ -857,7 +862,6 @@ impl FromWithTcx<ItemType> for ItemKind {
             Enum => ItemKind::Enum,
             Function | TyMethod | Method => ItemKind::Function,
             TypeAlias => ItemKind::TypeAlias,
-            OpaqueTy => ItemKind::OpaqueTy,
             Static => ItemKind::Static,
             Constant => ItemKind::Constant,
             Trait => ItemKind::Trait,
diff --git a/src/librustdoc/json/import_finder.rs b/src/librustdoc/json/import_finder.rs
index 982370aa21c..976a7fd69ae 100644
--- a/src/librustdoc/json/import_finder.rs
+++ b/src/librustdoc/json/import_finder.rs
@@ -1,9 +1,7 @@
 use rustc_hir::def_id::DefIdSet;
 
-use crate::{
-    clean::{self, Import, ImportSource, Item},
-    fold::DocFolder,
-};
+use crate::clean::{self, Import, ImportSource, Item};
+use crate::fold::DocFolder;
 
 /// Get the id's of all items that are `pub use`d in the crate.
 ///
diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs
index 0ef24818515..ea191dc89cf 100644
--- a/src/librustdoc/json/mod.rs
+++ b/src/librustdoc/json/mod.rs
@@ -18,7 +18,6 @@ use rustc_hir::def_id::{DefId, DefIdSet};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_span::def_id::LOCAL_CRATE;
-
 use rustdoc_json_types as types;
 
 use crate::clean::types::{ExternalCrate, ExternalLocation};
@@ -185,7 +184,6 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
                 | types::ItemEnum::TraitAlias(_)
                 | types::ItemEnum::Impl(_)
                 | types::ItemEnum::TypeAlias(_)
-                | types::ItemEnum::OpaqueTy(_)
                 | types::ItemEnum::Constant { .. }
                 | types::ItemEnum::Static(_)
                 | types::ItemEnum::ForeignType
@@ -218,13 +216,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
     fn after_krate(&mut self) -> Result<(), Error> {
         debug!("Done with crate");
 
-        debug!("Adding Primitive impls");
-        for primitive in Rc::clone(&self.cache).primitive_locations.values() {
-            self.get_impls(*primitive);
-        }
-
         let e = ExternalCrate { crate_num: LOCAL_CRATE };
-
         let index = (*self.index).clone().into_inner();
 
         debug!("Constructing Output");
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index fb4cd218b84..e651501a184 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -75,7 +75,8 @@ extern crate jemalloc_sys;
 use std::env::{self, VarError};
 use std::io::{self, IsTerminal};
 use std::process;
-use std::sync::{atomic::AtomicBool, Arc};
+use std::sync::atomic::AtomicBool;
+use std::sync::Arc;
 
 use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, FatalError};
 use rustc_interface::interface;
diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs
index 5a8fd3ebb9c..754ba58648d 100644
--- a/src/librustdoc/lint.rs
+++ b/src/librustdoc/lint.rs
@@ -1,10 +1,10 @@
+use std::sync::LazyLock as Lazy;
+
 use rustc_data_structures::fx::FxHashMap;
 use rustc_lint::LintStore;
 use rustc_lint_defs::{declare_tool_lint, Lint, LintId};
 use rustc_session::{lint, Session};
 
-use std::sync::LazyLock as Lazy;
-
 /// This function is used to setup the lint initialization. By default, in rustdoc, everything
 /// is "allowed". Depending if we run in test mode or not, we want some of them to be at their
 /// default level. For example, the "INVALID_CODEBLOCK_ATTRIBUTES" lint is activated in both
diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs
index 9e576002dc3..d6eef43902c 100644
--- a/src/librustdoc/passes/calculate_doc_coverage.rs
+++ b/src/librustdoc/passes/calculate_doc_coverage.rs
@@ -1,11 +1,8 @@
 //! Calculates information used for the --show-coverage flag.
 
-use crate::clean;
-use crate::core::DocContext;
-use crate::html::markdown::{find_testable_code, ErrorCodes};
-use crate::passes::check_doc_test_visibility::{should_have_doc_example, Tests};
-use crate::passes::Pass;
-use crate::visit::DocVisitor;
+use std::collections::BTreeMap;
+use std::ops;
+
 use rustc_hir as hir;
 use rustc_lint::builtin::MISSING_DOCS;
 use rustc_middle::lint::LintLevelSource;
@@ -13,8 +10,12 @@ use rustc_session::lint;
 use rustc_span::FileName;
 use serde::Serialize;
 
-use std::collections::BTreeMap;
-use std::ops;
+use crate::clean;
+use crate::core::DocContext;
+use crate::html::markdown::{find_testable_code, ErrorCodes};
+use crate::passes::check_doc_test_visibility::{should_have_doc_example, Tests};
+use crate::passes::Pass;
+use crate::visit::DocVisitor;
 
 pub(crate) const CALCULATE_DOC_COVERAGE: Pass = Pass {
     name: "calculate-doc-coverage",
diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs
index 0437f5e5fd8..d78afdffc62 100644
--- a/src/librustdoc/passes/check_doc_test_visibility.rs
+++ b/src/librustdoc/passes/check_doc_test_visibility.rs
@@ -5,6 +5,10 @@
 //! - MISSING_DOC_CODE_EXAMPLES: this lint is **UNSTABLE** and looks for public items missing doctests.
 //! - PRIVATE_DOC_TESTS: this lint is **STABLE** and looks for private items with doctests.
 
+use rustc_hir as hir;
+use rustc_middle::lint::LintLevelSource;
+use rustc_session::lint;
+
 use super::Pass;
 use crate::clean;
 use crate::clean::utils::inherits_doc_hidden;
@@ -12,9 +16,6 @@ use crate::clean::*;
 use crate::core::DocContext;
 use crate::html::markdown::{find_testable_code, ErrorCodes, Ignore, LangString, MdRelLine};
 use crate::visit::DocVisitor;
-use rustc_hir as hir;
-use rustc_middle::lint::LintLevelSource;
-use rustc_session::lint;
 
 pub(crate) const CHECK_DOC_TEST_VISIBILITY: Pass = Pass {
     name: "check_doc_test_visibility",
@@ -62,7 +63,7 @@ pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -
                 | clean::AssocTypeItem(..)
                 | clean::TypeAliasItem(_)
                 | clean::StaticItem(_)
-                | clean::ConstantItem(_, _, _)
+                | clean::ConstantItem(..)
                 | clean::ExternCrateItem { .. }
                 | clean::ImportItem(_)
                 | clean::PrimitiveItem(_)
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 37f7e7ed385..9c7eee4040b 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -2,12 +2,15 @@
 //!
 //! [RFC 1946]: https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md
 
+use std::borrow::Cow;
+use std::fmt::Display;
+use std::mem;
+use std::ops::Range;
+
 use pulldown_cmark::LinkType;
 use rustc_ast::util::comments::may_have_doc_links;
-use rustc_data_structures::{
-    fx::{FxHashMap, FxHashSet},
-    intern::Interned,
-};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::intern::Interned;
 use rustc_errors::{Applicability, Diag, DiagMessage};
 use rustc_hir::def::Namespace::*;
 use rustc_hir::def::{DefKind, Namespace, PerNS};
@@ -15,9 +18,9 @@ use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
 use rustc_hir::{Mutability, Safety};
 use rustc_middle::ty::{Ty, TyCtxt};
 use rustc_middle::{bug, span_bug, ty};
-use rustc_resolve::rustdoc::{has_primitive_or_keyword_docs, prepare_to_doc_link_resolution};
 use rustc_resolve::rustdoc::{
-    source_span_for_markdown_range, strip_generics_from_path, MalformedGenerics,
+    has_primitive_or_keyword_docs, prepare_to_doc_link_resolution, source_span_for_markdown_range,
+    strip_generics_from_path, MalformedGenerics,
 };
 use rustc_session::lint::Lint;
 use rustc_span::hygiene::MacroKind;
@@ -25,13 +28,8 @@ use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::BytePos;
 use smallvec::{smallvec, SmallVec};
 
-use std::borrow::Cow;
-use std::fmt::Display;
-use std::mem;
-use std::ops::Range;
-
-use crate::clean::{self, utils::find_nearest_parent_module};
-use crate::clean::{Crate, Item, ItemLink, PrimitiveType};
+use crate::clean::utils::find_nearest_parent_module;
+use crate::clean::{self, Crate, Item, ItemLink, PrimitiveType};
 use crate::core::DocContext;
 use crate::html::markdown::{markdown_links, MarkdownLink, MarkdownLinkRange};
 use crate::lint::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS};
diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index 9ac9941e521..1f00891ffa1 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -2,17 +2,17 @@
 //! defines a struct that implements a trait, this pass will note that the
 //! struct implements that trait.
 
+use rustc_data_structures::fx::FxHashSet;
+use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LOCAL_CRATE};
+use rustc_middle::ty;
+use rustc_span::symbol::sym;
+
 use super::Pass;
 use crate::clean::*;
 use crate::core::DocContext;
 use crate::formats::cache::Cache;
 use crate::visit::DocVisitor;
 
-use rustc_data_structures::fx::FxHashSet;
-use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LOCAL_CRATE};
-use rustc_middle::ty;
-use rustc_span::symbol::sym;
-
 pub(crate) const COLLECT_TRAIT_IMPLS: Pass = Pass {
     name: "collect-trait-impls",
     run: collect_trait_impls,
diff --git a/src/librustdoc/passes/lint/bare_urls.rs b/src/librustdoc/passes/lint/bare_urls.rs
index a4ba718789c..a0a369a7b85 100644
--- a/src/librustdoc/passes/lint/bare_urls.rs
+++ b/src/librustdoc/passes/lint/bare_urls.rs
@@ -1,16 +1,18 @@
 //! Detects links that are not linkified, e.g., in Markdown such as `Go to https://example.com/.`
 //! Suggests wrapping the link with angle brackets: `Go to <https://example.com/>.` to linkify it.
 
-use crate::clean::*;
-use crate::core::DocContext;
-use crate::html::markdown::main_body_opts;
 use core::ops::Range;
+use std::mem;
+use std::sync::LazyLock;
+
 use pulldown_cmark::{Event, Parser, Tag};
 use regex::Regex;
 use rustc_errors::Applicability;
 use rustc_resolve::rustdoc::source_span_for_markdown_range;
-use std::mem;
-use std::sync::LazyLock;
+
+use crate::clean::*;
+use crate::core::DocContext;
+use crate::html::markdown::main_body_opts;
 
 pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item) {
     let Some(hir_id) = DocContext::as_local_hir_id(cx.tcx, item.item_id) else {
diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs
index afeb7111e15..ef05befdddc 100644
--- a/src/librustdoc/passes/lint/check_code_block_syntax.rs
+++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs
@@ -1,11 +1,9 @@
 //! Validates syntax inside Rust code blocks (\`\`\`rust).
 
 use rustc_data_structures::sync::{Lock, Lrc};
-use rustc_errors::{
-    emitter::Emitter,
-    translation::{to_fluent_args, Translate},
-    Applicability, DiagCtxt, DiagInner, LazyFallbackBundle,
-};
+use rustc_errors::emitter::Emitter;
+use rustc_errors::translation::{to_fluent_args, Translate};
+use rustc_errors::{Applicability, DiagCtxt, DiagInner, LazyFallbackBundle};
 use rustc_parse::{source_str_to_stream, unwrap_or_emit_fatal};
 use rustc_resolve::rustdoc::source_span_for_markdown_range;
 use rustc_session::parse::ParseSess;
diff --git a/src/librustdoc/passes/lint/html_tags.rs b/src/librustdoc/passes/lint/html_tags.rs
index 87dfa5d5389..6f9e9d36a5c 100644
--- a/src/librustdoc/passes/lint/html_tags.rs
+++ b/src/librustdoc/passes/lint/html_tags.rs
@@ -1,15 +1,15 @@
 //! 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 std::iter::Peekable;
+use std::ops::Range;
+use std::str::CharIndices;
 
 use pulldown_cmark::{BrokenLink, Event, LinkType, Parser, Tag, TagEnd};
 use rustc_resolve::rustdoc::source_span_for_markdown_range;
 
-use std::iter::Peekable;
-use std::ops::Range;
-use std::str::CharIndices;
+use crate::clean::*;
+use crate::core::DocContext;
+use crate::html::markdown::main_body_opts;
 
 pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) {
     let tcx = cx.tcx;
diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs
index b36b41c9f2d..0a90c039dfb 100644
--- a/src/librustdoc/passes/lint/redundant_explicit_links.rs
+++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs
@@ -12,8 +12,7 @@ use rustc_resolve::rustdoc::{prepare_to_doc_link_resolution, source_span_for_mar
 use rustc_span::def_id::DefId;
 use rustc_span::Symbol;
 
-use crate::clean::utils::find_nearest_parent_module;
-use crate::clean::utils::inherits_doc_hidden;
+use crate::clean::utils::{find_nearest_parent_module, inherits_doc_hidden};
 use crate::clean::Item;
 use crate::core::DocContext;
 use crate::html::markdown::main_body_opts;
diff --git a/src/librustdoc/passes/lint/unescaped_backticks.rs b/src/librustdoc/passes/lint/unescaped_backticks.rs
index be9670077d1..a6c8db16f82 100644
--- a/src/librustdoc/passes/lint/unescaped_backticks.rs
+++ b/src/librustdoc/passes/lint/unescaped_backticks.rs
@@ -1,13 +1,15 @@
 //! Detects unescaped backticks (\`) in doc comments.
 
-use crate::clean::Item;
-use crate::core::DocContext;
-use crate::html::markdown::main_body_opts;
+use std::ops::Range;
+
 use pulldown_cmark::{BrokenLink, Event, Parser};
 use rustc_errors::Diag;
 use rustc_lint_defs::Applicability;
 use rustc_resolve::rustdoc::source_span_for_markdown_range;
-use std::ops::Range;
+
+use crate::clean::Item;
+use crate::core::DocContext;
+use crate::html::markdown::main_body_opts;
 
 pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) {
     let tcx = cx.tcx;
diff --git a/src/librustdoc/passes/lint/unportable_markdown.rs b/src/librustdoc/passes/lint/unportable_markdown.rs
index 5f185377634..87fe0055883 100644
--- a/src/librustdoc/passes/lint/unportable_markdown.rs
+++ b/src/librustdoc/passes/lint/unportable_markdown.rs
@@ -10,13 +10,14 @@
 //!
 //! <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 std::collections::{BTreeMap, BTreeSet};
+
 use rustc_lint_defs::Applicability;
 use rustc_resolve::rustdoc::source_span_for_markdown_range;
-use std::collections::{BTreeMap, BTreeSet};
+use {pulldown_cmark as cmarkn, pulldown_cmark_old as cmarko};
+
+use crate::clean::Item;
+use crate::core::DocContext;
 
 pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) {
     let tcx = cx.tcx;
diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs
index 8de7f2379b4..5aa6a5ee604 100644
--- a/src/librustdoc/passes/propagate_doc_cfg.rs
+++ b/src/librustdoc/passes/propagate_doc_cfg.rs
@@ -2,6 +2,8 @@
 
 use std::sync::Arc;
 
+use rustc_hir::def_id::LocalDefId;
+
 use crate::clean::cfg::Cfg;
 use crate::clean::inline::{load_attrs, merge_attrs};
 use crate::clean::{Crate, Item, ItemKind};
@@ -9,8 +11,6 @@ use crate::core::DocContext;
 use crate::fold::DocFolder;
 use crate::passes::Pass;
 
-use rustc_hir::def_id::LocalDefId;
-
 pub(crate) const PROPAGATE_DOC_CFG: Pass = Pass {
     name: "propagate-doc-cfg",
     run: propagate_doc_cfg,
diff --git a/src/librustdoc/passes/strip_aliased_non_local.rs b/src/librustdoc/passes/strip_aliased_non_local.rs
index ac7d422ec80..e1dd2d3af0f 100644
--- a/src/librustdoc/passes/strip_aliased_non_local.rs
+++ b/src/librustdoc/passes/strip_aliased_non_local.rs
@@ -1,5 +1,4 @@
-use rustc_middle::ty::TyCtxt;
-use rustc_middle::ty::Visibility;
+use rustc_middle::ty::{TyCtxt, Visibility};
 
 use crate::clean;
 use crate::clean::Item;
diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs
index 81a90ed498a..faf42b3aab1 100644
--- a/src/librustdoc/passes/strip_hidden.rs
+++ b/src/librustdoc/passes/strip_hidden.rs
@@ -1,9 +1,10 @@
 //! Strip all doc(hidden) items from the output.
 
+use std::mem;
+
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::sym;
-use std::mem;
 
 use crate::clean;
 use crate::clean::utils::inherits_doc_hidden;
diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs
index 1cf80a0d80c..f807c3362c4 100644
--- a/src/librustdoc/passes/stripper.rs
+++ b/src/librustdoc/passes/stripper.rs
@@ -1,8 +1,9 @@
 //! A collection of utility functions for the `strip_*` passes.
 
+use std::mem;
+
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::{TyCtxt, Visibility};
-use std::mem;
 
 use crate::clean::utils::inherits_doc_hidden;
 use crate::clean::{self, Item, ItemId, ItemIdSet};
@@ -49,8 +50,7 @@ impl<'a, 'tcx> DocFolder for Stripper<'a, 'tcx> {
                 return Some(ret);
             }
             // These items can all get re-exported
-            clean::OpaqueTyItem(..)
-            | clean::TypeAliasItem(..)
+            clean::TypeAliasItem(..)
             | clean::StaticItem(..)
             | clean::StructItem(..)
             | clean::EnumItem(..)
@@ -95,7 +95,14 @@ impl<'a, 'tcx> DocFolder for Stripper<'a, 'tcx> {
             }
 
             clean::ModuleItem(..) => {
-                if i.item_id.is_local() && i.visibility(self.tcx) != Some(Visibility::Public) {
+                if i.item_id.is_local()
+                    && !is_item_reachable(
+                        self.tcx,
+                        self.is_json_output,
+                        self.effective_visibilities,
+                        i.item_id,
+                    )
+                {
                     debug!("Stripper: stripping module {:?}", i.name);
                     let old = mem::replace(&mut self.update_retained, false);
                     let ret = strip_item(self.fold_item_recur(i));
diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs
index 5a595e03953..f001fb26b81 100644
--- a/src/librustdoc/scrape_examples.rs
+++ b/src/librustdoc/scrape_examples.rs
@@ -1,35 +1,27 @@
 //! This module analyzes crates to find call sites that can serve as examples in the documentation.
 
-use crate::clean;
-use crate::config;
-use crate::formats;
-use crate::formats::renderer::FormatRenderer;
-use crate::html::render::Context;
+use std::fs;
+use std::path::PathBuf;
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::DiagCtxtHandle;
-use rustc_hir::{
-    self as hir,
-    intravisit::{self, Visitor},
-};
+use rustc_hir::intravisit::{self, Visitor};
+use rustc_hir::{self as hir};
 use rustc_interface::interface;
 use rustc_macros::{Decodable, Encodable};
 use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{self, TyCtxt};
-use rustc_serialize::{
-    opaque::{FileEncoder, MemDecoder},
-    Decodable, Encodable,
-};
+use rustc_serialize::opaque::{FileEncoder, MemDecoder};
+use rustc_serialize::{Decodable, Encodable};
 use rustc_session::getopts;
-use rustc_span::{
-    def_id::{CrateNum, DefPathHash, LOCAL_CRATE},
-    edition::Edition,
-    BytePos, FileName, SourceFile,
-};
+use rustc_span::def_id::{CrateNum, DefPathHash, LOCAL_CRATE};
+use rustc_span::edition::Edition;
+use rustc_span::{BytePos, FileName, SourceFile};
 
-use std::fs;
-use std::path::PathBuf;
+use crate::formats::renderer::FormatRenderer;
+use crate::html::render::Context;
+use crate::{clean, config, formats};
 
 #[derive(Debug, Clone)]
 pub(crate) struct ScrapeExamplesOptions {
diff --git a/src/librustdoc/theme.rs b/src/librustdoc/theme.rs
index 2fa54a9cd81..409728a8e86 100644
--- a/src/librustdoc/theme.rs
+++ b/src/librustdoc/theme.rs
@@ -1,10 +1,10 @@
-use rustc_data_structures::fx::FxHashMap;
 use std::collections::hash_map::Entry;
 use std::fs;
 use std::iter::Peekable;
 use std::path::Path;
 use std::str::Chars;
 
+use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::DiagCtxtHandle;
 
 #[cfg(test)]
diff --git a/src/librustdoc/visit.rs b/src/librustdoc/visit.rs
index b335dc5bd16..430bbe991ea 100644
--- a/src/librustdoc/visit.rs
+++ b/src/librustdoc/visit.rs
@@ -26,9 +26,8 @@ pub(crate) trait DocVisitor: Sized {
             | ImportItem(_)
             | FunctionItem(_)
             | TypeAliasItem(_)
-            | OpaqueTyItem(_)
             | StaticItem(_)
-            | ConstantItem(_, _, _)
+            | ConstantItem(..)
             | TraitAliasItem(_)
             | TyMethodItem(_)
             | MethodItem(_, _)
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 886df82e5b6..d7a4a0d88ac 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -1,6 +1,8 @@
 //! The Rust AST Visitor. Extracts useful information and massages it into a form
 //! usable for `clean`.
 
+use std::mem;
+
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
@@ -14,10 +16,9 @@ use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
 
-use std::mem;
-
+use crate::clean::cfg::Cfg;
 use crate::clean::utils::{inherits_doc_hidden, should_ignore_res};
-use crate::clean::{cfg::Cfg, reexport_chain, AttributesExt, NestedAttributesExt};
+use crate::clean::{reexport_chain, AttributesExt, NestedAttributesExt};
 use crate::core;
 
 /// This module is used to store stuff from Rust's AST in a more convenient
diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs
index 82c97466111..3e66ed9f56d 100644
--- a/src/librustdoc/visit_lib.rs
+++ b/src/librustdoc/visit_lib.rs
@@ -1,8 +1,9 @@
-use crate::core::DocContext;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, DefIdSet};
 use rustc_middle::ty::TyCtxt;
 
+use crate::core::DocContext;
+
 // FIXME: this may not be exhaustive, but is sufficient for rustdocs current uses
 
 #[derive(Default)]
diff --git a/src/llvm-project b/src/llvm-project
-Subproject c54cff0e6e4d1a0d0a2df7c1ce3d96cdd554763
+Subproject 57ae1a3474057fead2c438928ed368b3740bf0e
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index 6fd23b60c8a..999134a4090 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -3,14 +3,21 @@
 //! These types are the public API exposed through the `--output-format json` flag. The [`Crate`]
 //! struct is the root of the JSON blob and all other items are contained within.
 
+use std::path::PathBuf;
+
 use rustc_hash::FxHashMap;
 use serde::{Deserialize, Serialize};
-use std::path::PathBuf;
 
-/// rustdoc format-version.
-pub const FORMAT_VERSION: u32 = 32;
+/// The version of JSON output that this crate represents.
+///
+/// This integer is incremented with every breaking change to the API,
+/// and is returned along with the JSON blob as [`Crate::format_version`].
+/// Consuming code should assert that this value matches the format version(s) that it supports.
+pub const FORMAT_VERSION: u32 = 33;
 
-/// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
+/// 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
 /// tools to find or link to them.
 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
@@ -33,13 +40,18 @@ pub struct Crate {
     pub format_version: u32,
 }
 
+/// Metadata of a crate, either the same crate on which `rustdoc` was invoked, or its dependency.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct ExternalCrate {
+    /// The name of the crate.
     pub name: String,
+    /// The root URL at which the crate's documentation lives.
     pub html_root_url: Option<String>,
 }
 
-/// For external (not defined in the local crate) items, you don't get the same level of
+/// Information about an external (not defined in the local crate) [`Item`].
+///
+/// For external items, you don't get the same level of
 /// information. This struct should contain enough to generate a link/reference to the item in
 /// question, or can be used by a tool that takes the json output of multiple crates to find
 /// the actual item definition with all the relevant info.
@@ -60,6 +72,10 @@ pub struct ItemSummary {
     pub kind: ItemKind,
 }
 
+/// Anything that can hold documentation - modules, structs, enums, functions, traits, etc.
+///
+/// The `Item` data type holds fields that can apply to any of these,
+/// and leaves kind-specific details (like function args or enum variants) to the `inner` field.
 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
 pub struct Item {
     /// The unique identifier of this item. Can be used to find this item in various mappings.
@@ -82,10 +98,13 @@ pub struct Item {
     pub links: FxHashMap<String, Id>,
     /// Stringified versions of the attributes on this item (e.g. `"#[inline]"`)
     pub attrs: Vec<String>,
+    /// Information about the item’s deprecation, if present.
     pub deprecation: Option<Deprecation>,
+    /// The type-specific fields describing this item.
     pub inner: ItemEnum,
 }
 
+/// A range of source code.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Span {
     /// The path to the source file for this span relative to the path `rustdoc` was invoked with.
@@ -96,28 +115,39 @@ pub struct Span {
     pub end: (usize, usize),
 }
 
+/// Information about the deprecation of an [`Item`].
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Deprecation {
+    /// Usually a version number when this [`Item`] first became deprecated.
     pub since: Option<String>,
+    /// The reason for deprecation and/or what alternatives to use.
     pub note: Option<String>,
 }
 
+/// Visibility of an [`Item`].
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum Visibility {
+    /// Explicitly public visibility set with `pub`.
     Public,
     /// For the most part items are private by default. The exceptions are associated items of
     /// public traits and variants of public enums.
     Default,
+    /// Explicitly crate-wide visibility set with `pub(crate)`
     Crate,
-    /// For `pub(in path)` visibility. `parent` is the module it's restricted to and `path` is how
-    /// that module was referenced (like `"super::super"` or `"crate::foo::bar"`).
+    /// For `pub(in path)` visibility.
     Restricted {
+        /// ID of the module to which this visibility restricts items.
         parent: Id,
+        /// The path with which [`parent`] was referenced
+        /// (like `super::super` or `crate::foo::bar`).
+        ///
+        /// [`parent`]: Visibility::Restricted::parent
         path: String,
     },
 }
 
+/// Dynamic trait object type (`dyn Trait`).
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct DynTrait {
     /// All the traits implemented. One of them is the vtable, and the rest must be auto traits.
@@ -132,64 +162,133 @@ pub struct DynTrait {
     pub lifetime: Option<String>,
 }
 
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 /// A trait and potential HRTBs
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct PolyTrait {
+    /// The path to the trait.
     #[serde(rename = "trait")]
     pub trait_: Path,
     /// Used for Higher-Rank Trait Bounds (HRTBs)
     /// ```text
     /// dyn for<'a> Fn() -> &'a i32"
     ///     ^^^^^^^
-    ///       |
-    ///       this part
     /// ```
     pub generic_params: Vec<GenericParamDef>,
 }
 
+/// A set of generic arguments provided to a path segment, e.g.
+///
+/// ```text
+/// std::option::Option::<u32>::None
+///                      ^^^^^
+/// ```
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum GenericArgs {
-    /// <'a, 32, B: Copy, C = u32>
-    AngleBracketed { args: Vec<GenericArg>, bindings: Vec<TypeBinding> },
-    /// Fn(A, B) -> C
-    Parenthesized { inputs: Vec<Type>, output: Option<Type> },
+    /// `<'a, 32, B: Copy, C = u32>`
+    AngleBracketed {
+        /// The list of each argument on this type.
+        /// ```text
+        /// <'a, 32, B: Copy, C = u32>
+        ///  ^^^^^^
+        /// ```
+        args: Vec<GenericArg>,
+        /// Associated type or constant bindings (e.g. `Item=i32` or `Item: Clone`) for this type.
+        bindings: Vec<TypeBinding>,
+    },
+    /// `Fn(A, B) -> C`
+    Parenthesized {
+        /// The input types, enclosed in parentheses.
+        inputs: Vec<Type>,
+        /// The output type provided after the `->`, if present.
+        output: Option<Type>,
+    },
 }
 
+/// One argument in a list of generic arguments to a path segment.
+///
+/// Part of [`GenericArgs`].
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum GenericArg {
+    /// A lifetime argument.
+    /// ```text
+    /// std::borrow::Cow<'static, str>
+    ///                  ^^^^^^^
+    /// ```
     Lifetime(String),
+    /// A type argument.
+    /// ```text
+    /// std::borrow::Cow<'static, str>
+    ///                           ^^^
+    /// ```
     Type(Type),
+    /// A constant as a generic argument.
+    /// ```text
+    /// core::array::IntoIter<u32, { 640 * 1024 }>
+    ///                            ^^^^^^^^^^^^^^
+    /// ```
     Const(Constant),
+    /// A generic argument that's explicitly set to be inferred.
+    /// ```text
+    /// std::vec::Vec::<_>::new()
+    ///                 ^
+    /// ```
     Infer,
 }
 
+/// A constant.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Constant {
+    /// The stringified expression of this constant. Note that its mapping to the original
+    /// source code is unstable and it's not guaranteed that it'll match the source code.
     pub expr: String,
+    /// The value of the evaluated expression for this constant, which is only computed for numeric
+    /// types.
     pub value: Option<String>,
+    /// Whether this constant is a bool, numeric, string, or char literal.
     pub is_literal: bool,
 }
 
+/// Describes a bound applied to an associated type/constant.
+///
+/// Example:
+/// ```text
+/// IntoIterator<Item = u32, IntoIter: Clone>
+///              ^^^^^^^^^^  ^^^^^^^^^^^^^^^
+/// ```
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct TypeBinding {
+    /// The name of the associated type/constant.
     pub name: String,
+    /// Arguments provided to the associated type/constant.
     pub args: GenericArgs,
+    /// The kind of bound applied to the associated type/constant.
     pub binding: TypeBindingKind,
 }
 
+/// The way in which an associate type/constant is bound.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum TypeBindingKind {
+    /// The required value/type is specified exactly. e.g.
+    /// ```text
+    /// Iterator<Item = u32, IntoIter: DoubleEndedIterator>
+    ///          ^^^^^^^^^^
+    /// ```
     Equality(Term),
+    /// The type is required to satisfy a set of bounds.
+    /// ```text
+    /// Iterator<Item = u32, IntoIter: DoubleEndedIterator>
+    ///                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    /// ```
     Constraint(Vec<GenericBound>),
 }
 
 /// An opaque identifier for an item.
 ///
-/// It can be used to lookup in [Crate::index] or [Crate::paths] to resolve it
-/// to an [Item].
+/// It can be used to lookup in [`Crate::index`] or [`Crate::paths`] to resolve it
+/// to an [`Item`].
 ///
 /// Id's are only valid within a single JSON blob. They cannot be used to
 /// resolve references between the JSON output's for different crates.
@@ -201,115 +300,228 @@ pub enum TypeBindingKind {
 // FIXME(aDotInTheVoid): Consider making this non-public in rustdoc-types.
 pub struct Id(pub String);
 
+/// The fundamental kind of an item. Unlike [`ItemEnum`], this does not carry any aditional info.
+///
+/// Part of [`ItemSummary`].
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum ItemKind {
+    /// A module declaration, e.g. `mod foo;` or `mod foo {}`
     Module,
+    /// A crate imported via the `extern crate` syntax.
     ExternCrate,
+    /// An import of 1 or more items into scope, using the `use` keyword.
     Import,
+    /// A `struct` declaration.
     Struct,
+    /// A field of a struct.
     StructField,
+    /// A `union` declaration.
     Union,
+    /// An `enum` declaration.
     Enum,
+    /// A variant of a enum.
     Variant,
+    /// A function declaration, e.g. `fn f() {}`
     Function,
+    /// A type alias declaration, e.g. `type Pig = std::borrow::Cow<'static, str>;`
     TypeAlias,
-    OpaqueTy,
+    /// The declaration of a constant, e.g. `const GREETING: &str = "Hi :3";`
     Constant,
+    /// A `trait` declaration.
     Trait,
+    /// A trait alias declaration, e.g. `trait Int = Add + Sub + Mul + Div;`
+    ///
+    /// See [the tracking issue](https://github.com/rust-lang/rust/issues/41517)
     TraitAlias,
+    /// An `impl` block.
     Impl,
+    /// A `static` declaration.
     Static,
+    /// `type`s from an `extern` block.
+    ///
+    /// See [the tracking issue](https://github.com/rust-lang/rust/issues/43467)
     ForeignType,
+    /// A macro declaration.
+    ///
+    /// Corresponds to either `ItemEnum::Macro(_)`
+    /// or `ItemEnum::ProcMacro(ProcMacro { kind: MacroKind::Bang })`
     Macro,
+    /// A procedural macro attribute.
+    ///
+    /// Corresponds to `ItemEnum::ProcMacro(ProcMacro { kind: MacroKind::Attr })`
     ProcAttribute,
+    /// A procedural macro usable in the `#[derive()]` attribute.
+    ///
+    /// Corresponds to `ItemEnum::ProcMacro(ProcMacro { kind: MacroKind::Derive })`
     ProcDerive,
+    /// An associated constant of a trait or a type.
     AssocConst,
+    /// An associated type of a trait or a type.
     AssocType,
+    /// A primitive type, e.g. `u32`.
+    ///
+    /// [`Item`]s of this kind only come from the core library.
     Primitive,
+    /// A keyword declaration.
+    ///
+    /// [`Item`]s of this kind only come from the come library and exist solely
+    /// to carry documentation for the respective keywords.
     Keyword,
 }
 
+/// Specific fields of an item.
+///
+/// Part of [`Item`].
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum ItemEnum {
+    /// A module declaration, e.g. `mod foo;` or `mod foo {}`
     Module(Module),
+    /// A crate imported via the `extern crate` syntax.
     ExternCrate {
+        /// The name of the imported crate.
         name: String,
+        /// If the crate is renamed, this is its name in the crate.
         rename: Option<String>,
     },
+    /// An import of 1 or more items into scope, using the `use` keyword.
     Import(Import),
 
+    /// A `union` declaration.
     Union(Union),
+    /// A `struct` declaration.
     Struct(Struct),
+    /// A field of a struct.
     StructField(Type),
+    /// An `enum` declaration.
     Enum(Enum),
+    /// A variant of a enum.
     Variant(Variant),
 
+    /// A function declaration (including methods and other associated functions)
     Function(Function),
 
+    /// A `trait` declaration.
     Trait(Trait),
+    /// A trait alias declaration, e.g. `trait Int = Add + Sub + Mul + Div;`
+    ///
+    /// See [the tracking issue](https://github.com/rust-lang/rust/issues/41517)
     TraitAlias(TraitAlias),
+    /// An `impl` block.
     Impl(Impl),
 
+    /// A type alias declaration, e.g. `type Pig = std::borrow::Cow<'static, str>;`
     TypeAlias(TypeAlias),
-    OpaqueTy(OpaqueTy),
+    /// The declaration of a constant, e.g. `const GREETING: &str = "Hi :3";`
     Constant {
+        /// The type of the constant.
         #[serde(rename = "type")]
         type_: Type,
+        /// The declared constant itself.
         #[serde(rename = "const")]
         const_: Constant,
     },
 
+    /// A declaration of a `static`.
     Static(Static),
 
-    /// `type`s from an extern block
+    /// `type`s from an `extern` block.
+    ///
+    /// See [the tracking issue](https://github.com/rust-lang/rust/issues/43467)
     ForeignType,
 
-    /// Declarative macro_rules! macro
+    /// A macro_rules! declarative macro. Contains a single string with the source
+    /// representation of the macro with the patterns stripped.
     Macro(String),
+    /// A procedural macro.
     ProcMacro(ProcMacro),
 
+    /// A primitive type, e.g. `u32`.
+    ///
+    /// [`Item`]s of this kind only come from the core library.
     Primitive(Primitive),
 
+    /// An associated constant of a trait or a type.
     AssocConst {
+        /// The type of the constant.
         #[serde(rename = "type")]
         type_: Type,
-        /// e.g. `const X: usize = 5;`
+        /// The stringified expression for the default value, if provided, e.g.
+        /// ```rust
+        /// const X: usize = 640 * 1024;
+        /// //               ^^^^^^^^^^
+        /// ```
         default: Option<String>,
     },
+    /// An associated type of a trait or a type.
     AssocType {
+        /// The generic parameters and where clauses on ahis associated type.
         generics: Generics,
+        /// The bounds for this associated type. e.g.
+        /// ```rust
+        /// trait IntoIterator {
+        ///     type Item;
+        ///     type IntoIter: Iterator<Item = Self::Item>;
+        /// //                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+        /// }
+        /// ```
         bounds: Vec<GenericBound>,
-        /// e.g. `type X = usize;`
+        /// The default for this type, if provided, e.g.
+        /// ```rust
+        /// type X = usize;
+        /// //       ^^^^^
+        /// ```
         default: Option<Type>,
     },
 }
 
+/// A module declaration, e.g. `mod foo;` or `mod foo {}`.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Module {
+    /// Whether this is the root item of a crate.
+    ///
+    /// This item doesn't correspond to any construction in the source code and is generated by the
+    /// compiler.
     pub is_crate: bool,
+    /// [`Item`]s declared inside this module.
     pub items: Vec<Id>,
     /// If `true`, this module is not part of the public API, but it contains
     /// items that are re-exported as public API.
     pub is_stripped: bool,
 }
 
+/// A `union`.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Union {
+    /// The generic parameters and where clauses on this union.
     pub generics: Generics,
+    /// Whether any fields have been removed from the result, due to being private or hidden.
     pub fields_stripped: bool,
+    /// The list of fields in the union.
+    ///
+    /// All of the corresponding [`Item`]s are of kind [`ItemEnum::StructField`].
     pub fields: Vec<Id>,
+    /// All impls (both of traits and inherent) for this union.
+    ///
+    /// All of the corresponding [`Item`]s are of kind [`ItemEnum::Impl`].
     pub impls: Vec<Id>,
 }
 
+/// A `struct`.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Struct {
+    /// The kind of the struct (e.g. unit, tuple-like or struct-like) and the data specific to it,
+    /// i.e. fields.
     pub kind: StructKind,
+    /// The generic parameters and where clauses on this struct.
     pub generics: Generics,
+    /// All impls (both of traits and inherent) for this struct.
+    /// All of the corresponding [`Item`]s are of kind [`ItemEnum::Impl`].
     pub impls: Vec<Id>,
 }
 
+/// The kind of a [`Struct`] and the data specific to it, i.e. fields.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum StructKind {
@@ -321,13 +533,14 @@ pub enum StructKind {
     Unit,
     /// A struct with unnamed fields.
     ///
+    /// All [`Id`]'s will point to [`ItemEnum::StructField`].
+    /// Unlike most of JSON, private and `#[doc(hidden)]` fields will be given as `None`
+    /// instead of being omitted, because order matters.
+    ///
     /// ```rust
     /// pub struct TupleStruct(i32);
     /// pub struct EmptyTupleStruct();
     /// ```
-    ///
-    /// All [`Id`]'s will point to [`ItemEnum::StructField`]. Private and
-    /// `#[doc(hidden)]` fields will be given as `None`
     Tuple(Vec<Option<Id>>),
     /// A struct with named fields.
     ///
@@ -335,17 +548,32 @@ pub enum StructKind {
     /// pub struct PlainStruct { x: i32 }
     /// pub struct EmptyPlainStruct {}
     /// ```
-    Plain { fields: Vec<Id>, fields_stripped: bool },
+    Plain {
+        /// The list of fields in the struct.
+        ///
+        /// All of the corresponding [`Item`]s are of kind [`ItemEnum::StructField`].
+        fields: Vec<Id>,
+        /// Whether any fields have been removed from the result, due to being private or hidden.
+        fields_stripped: bool,
+    },
 }
 
+/// An `enum`.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Enum {
+    /// Information about the type parameters and `where` clauses of the enum.
     pub generics: Generics,
+    /// Whether any variants have been removed from the result, due to being private or hidden.
     pub variants_stripped: bool,
+    /// The list of variants in the enum.
+    ///
+    /// All of the corresponding [`Item`]s are of kind [`ItemEnum::Variant`]
     pub variants: Vec<Id>,
+    /// `impl`s for the enum.
     pub impls: Vec<Id>,
 }
 
+/// A variant of an enum.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Variant {
     /// Whether the variant is plain, a tuple-like, or struct-like. Contains the fields.
@@ -354,6 +582,7 @@ pub struct Variant {
     pub discriminant: Option<Discriminant>,
 }
 
+/// The kind of an [`Enum`] [`Variant`] and the data specific to it, i.e. fields.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum VariantKind {
@@ -368,7 +597,8 @@ pub enum VariantKind {
     Plain,
     /// A variant with unnamed fields.
     ///
-    /// Unlike most of json, `#[doc(hidden)]` fields will be given as `None`
+    /// All [`Id`]'s will point to [`ItemEnum::StructField`].
+    /// Unlike most of JSON, `#[doc(hidden)]` fields will be given as `None`
     /// instead of being omitted, because order matters.
     ///
     /// ```rust
@@ -386,9 +616,16 @@ pub enum VariantKind {
     ///     EmptyStructVariant {},
     /// }
     /// ```
-    Struct { fields: Vec<Id>, fields_stripped: bool },
+    Struct {
+        /// The list of variants in the enum.
+        /// All of the corresponding [`Item`]s are of kind [`ItemEnum::Variant`].
+        fields: Vec<Id>,
+        /// Whether any variants have been removed from the result, due to being private or hidden.
+        fields_stripped: bool,
+    },
 }
 
+/// The value that distinguishes a variant in an [`Enum`] from other variants.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Discriminant {
     /// The expression that produced the discriminant.
@@ -397,7 +634,7 @@ pub struct Discriminant {
     /// hexadecimal, and underscores), making it unsuitable to be machine
     /// interpreted.
     ///
-    /// In some cases, when the value is to complex, this may be `"{ _ }"`.
+    /// In some cases, when the value is too complex, this may be `"{ _ }"`.
     /// When this occurs is unstable, and may change without notice.
     pub expr: String,
     /// The numerical value of the discriminant. Stored as a string due to
@@ -406,62 +643,123 @@ pub struct Discriminant {
     pub value: String,
 }
 
+/// A set of fundamental properties of a function.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Header {
+    /// Is this function marked as `const`?
     #[serde(rename = "const")]
     pub const_: bool,
+    /// Is this function unsafe?
     #[serde(rename = "unsafe")]
     pub unsafe_: bool,
+    /// Is this function async?
     #[serde(rename = "async")]
     pub async_: bool,
+    /// The ABI used by the function.
     pub abi: Abi,
 }
 
+/// The ABI (Application Binary Interface) used by a function.
+///
+/// If a variant has an `unwind` field, this means the ABI that it represents can be specified in 2
+/// ways: `extern "_"` and `extern "_-unwind"`, and a value of `true` for that field signifies the
+/// latter variant.
+///
+/// See the [Rustonomicon section](https://doc.rust-lang.org/nightly/nomicon/ffi.html#ffi-and-unwinding)
+/// on unwinding for more info.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub enum Abi {
     // We only have a concrete listing here for stable ABI's because their are so many
     // See rustc_ast_passes::feature_gate::PostExpansionVisitor::check_abi for the list
+    /// The default ABI, but that can also be written explicitly with `extern "Rust"`.
     Rust,
+    /// Can be specified as `extern "C"` or, as a shorthand, just `extern`.
     C { unwind: bool },
+    /// Can be specified as `extern "cdecl"`.
     Cdecl { unwind: bool },
+    /// Can be specified as `extern "stdcall"`.
     Stdcall { unwind: bool },
+    /// Can be specified as `extern "fastcall"`.
     Fastcall { unwind: bool },
+    /// Can be specified as `extern "aapcs"`.
     Aapcs { unwind: bool },
+    /// Can be specified as `extern "win64"`.
     Win64 { unwind: bool },
+    /// Can be specifed as `extern "sysv64"`.
     SysV64 { unwind: bool },
+    /// Can be specified as `extern "system"`.
     System { unwind: bool },
+    /// Any other ABI, including unstable ones.
     Other(String),
 }
 
-/// Represents a function (including methods and other associated functions)
+/// A function declaration (including methods and other associated functions).
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Function {
+    /// Information about the function signature, or declaration.
     pub decl: FnDecl,
+    /// Information about the function’s type parameters and `where` clauses.
     pub generics: Generics,
+    /// Information about core properties of the function, e.g. whether it's `const`, its ABI, etc.
     pub header: Header,
+    /// Whether the function has a body, i.e. an implementation.
     pub has_body: bool,
 }
 
+/// Generic parameters accepted by an item and `where` clauses imposed on it and the parameters.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Generics {
+    /// A list of generic parameter definitions (e.g. `<T: Clone + Hash, U: Copy>`).
     pub params: Vec<GenericParamDef>,
+    /// A list of where predicates (e.g. `where T: Iterator, T::Item: Copy`).
     pub where_predicates: Vec<WherePredicate>,
 }
 
+/// One generic parameter accepted by an item.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct GenericParamDef {
+    /// Name of the parameter.
+    /// ```rust
+    /// fn f<'resource, Resource>(x: &'resource Resource) {}
+    /// //    ^^^^^^^^  ^^^^^^^^
+    /// ```
     pub name: String,
+    /// The kind of the parameter and data specific to a particular parameter kind, e.g. type
+    /// bounds.
     pub kind: GenericParamDefKind,
 }
 
+/// The kind of a [`GenericParamDef`].
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum GenericParamDefKind {
+    /// Denotes a lifetime parameter.
     Lifetime {
+        /// Lifetimes that this lifetime parameter is required to outlive.
+        ///
+        /// ```rust
+        /// fn f<'a, 'b, 'resource: 'a + 'b>(a: &'a str, b: &'b str, res: &'resource str) {}
+        /// //                      ^^^^^^^
+        /// ```
         outlives: Vec<String>,
     },
+
+    /// Denotes a type parameter.
     Type {
+        /// Bounds applied directly to the type. Note that the bounds from `where` clauses
+        /// that constrain this parameter won't appear here.
+        ///
+        /// ```rust
+        /// fn default2<T: Default>() -> [T; 2] where T: Clone { todo!() }
+        /// //             ^^^^^^^
+        /// ```
         bounds: Vec<GenericBound>,
+        /// The default type for this parameter, if provided, e.g.
+        ///
+        /// ```rust
+        /// trait PartialEq<Rhs = Self> {}
+        /// //                    ^^^^
+        /// ```
         default: Option<Type>,
         /// This is normally `false`, which means that this generic parameter is
         /// declared in the Rust source text.
@@ -488,43 +786,75 @@ pub enum GenericParamDefKind {
         /// the Rust source text.
         synthetic: bool,
     },
+
+    /// Denotes a constant parameter.
     Const {
+        /// The type of the constant as declared.
         #[serde(rename = "type")]
         type_: Type,
+        /// The stringified expression for the default value, if provided. It's not guaranteed that
+        /// it'll match the actual source code for the default value.
         default: Option<String>,
     },
 }
 
+/// One `where` clause.
+/// ```rust
+/// fn default<T>() -> T where T: Default { T::default() }
+/// //                         ^^^^^^^^^^
+/// ```
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum WherePredicate {
+    /// A type is expected to comply with a set of bounds
     BoundPredicate {
+        /// The type that's being constrained.
+        ///
+        /// ```rust
+        /// fn f<T>(x: T) where for<'a> &'a T: Iterator {}
+        /// //                              ^
+        /// ```
         #[serde(rename = "type")]
         type_: Type,
+        /// The set of bounds that constrain the type.
+        ///
+        /// ```rust
+        /// fn f<T>(x: T) where for<'a> &'a T: Iterator {}
+        /// //                                 ^^^^^^^^
+        /// ```
         bounds: Vec<GenericBound>,
         /// Used for Higher-Rank Trait Bounds (HRTBs)
-        /// ```text
-        /// where for<'a> &'a T: Iterator,"
-        ///       ^^^^^^^
-        ///       |
-        ///       this part
+        /// ```rust
+        /// fn f<T>(x: T) where for<'a> &'a T: Iterator {}
+        /// //                  ^^^^^^^
         /// ```
         generic_params: Vec<GenericParamDef>,
     },
+
+    /// A lifetime is expected to outlive other lifetimes.
     LifetimePredicate {
+        /// The name of the lifetime.
         lifetime: String,
+        /// The lifetimes that must be encompassed by the lifetime.
         outlives: Vec<String>,
     },
+
+    /// A type must exactly equal another type.
     EqPredicate {
+        /// The left side of the equation.
         lhs: Type,
+        /// The right side of the equation.
         rhs: Term,
     },
 }
 
+/// Either a trait bound or a lifetime bound.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum GenericBound {
+    /// A trait bound.
     TraitBound {
+        /// The full path to the trait.
         #[serde(rename = "trait")]
         trait_: Path,
         /// Used for Higher-Rank Trait Bounds (HRTBs)
@@ -535,79 +865,142 @@ pub enum GenericBound {
         ///          this part
         /// ```
         generic_params: Vec<GenericParamDef>,
+        /// The context for which a trait is supposed to be used, e.g. `const
         modifier: TraitBoundModifier,
     },
+    /// A lifetime bound, e.g.
+    /// ```rust
+    /// fn f<'a, T>(x: &'a str, y: &T) where T: 'a {}
+    /// //                                     ^^^
+    /// ```
     Outlives(String),
     /// `use<'a, T>` precise-capturing bound syntax
     Use(Vec<String>),
 }
 
+/// A set of modifiers applied to a trait.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum TraitBoundModifier {
+    /// Marks the absence of a modifier.
     None,
+    /// Indicates that the trait bound relaxes a trait bound applied to a parameter by default,
+    /// e.g. `T: Sized?`, the `Sized` trait is required for all generic type parameters by default
+    /// unless specified otherwise with this modifier.
     Maybe,
+    /// Indicates that the trait bound must be applicable in both a run-time and a compile-time
+    /// context.
     MaybeConst,
 }
 
+/// Either a type or a constant, usually stored as the right-hand side of an equation in places like
+/// [`TypeBinding`]
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum Term {
+    /// A type.
+    ///
+    /// ```rust
+    /// fn f(x: impl IntoIterator<Item = u32>) {}
+    /// //                               ^^^
+    /// ```
     Type(Type),
+    /// A constant.
+    ///
+    /// ```ignore (incomplete feature in the snippet)
+    /// trait Foo {
+    ///     const BAR: usize;
+    /// }
+    ///
+    /// fn f(x: impl Foo<BAR = 42>) {}
+    /// //                     ^^
+    /// ```
     Constant(Constant),
 }
 
+/// A type.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum Type {
-    /// Structs, enums, and unions
+    /// Structs, enums, unions and type aliases, e.g. `std::option::Option<u32>`
     ResolvedPath(Path),
+    /// Dynamic trait object type (`dyn Trait`).
     DynTrait(DynTrait),
-    /// Parameterized types
+    /// Parameterized types. The contained string is the name of the parameter.
     Generic(String),
-    /// Built in numeric (i*, u*, f*) types, bool, and char
+    /// Built-in numeric types (e.g. `u32`, `f32`), `bool`, `char`.
     Primitive(String),
-    /// `extern "ABI" fn`
+    /// A function pointer type, e.g. `fn(u32) -> u32`, `extern "C" fn() -> *const u8`
     FunctionPointer(Box<FunctionPointer>),
-    /// `(String, u32, Box<usize>)`
+    /// A tuple type, e.g. `(String, u32, Box<usize>)`
     Tuple(Vec<Type>),
-    /// `[u32]`
+    /// An unsized slice type, e.g. `[u32]`.
     Slice(Box<Type>),
-    /// [u32; 15]
+    /// An array type, e.g. `[u32; 15]`
     Array {
+        /// The type of the contained element.
         #[serde(rename = "type")]
         type_: Box<Type>,
+        /// The stringified expression that is the length of the array.
+        ///
+        /// Keep in mind that it's not guaranteed to match the actual source code of the expression.
         len: String,
     },
-    /// `u32 is 1..`
+    /// A pattern type, e.g. `u32 is 1..`
+    ///
+    /// See [the tracking issue](https://github.com/rust-lang/rust/issues/123646)
     Pat {
+        /// The base type, e.g. the `u32` in `u32 is 1..`
         #[serde(rename = "type")]
         type_: Box<Type>,
         #[doc(hidden)]
         __pat_unstable_do_not_use: String,
     },
-    /// `impl TraitA + TraitB + ...`
+    /// An opaque type that satisfies a set of bounds, `impl TraitA + TraitB + ...`
     ImplTrait(Vec<GenericBound>),
-    /// `_`
+    /// A type that's left to be inferred, `_`
     Infer,
-    /// `*mut u32`, `*u8`, etc.
+    /// A raw pointer type, e.g. `*mut u32`, `*const u8`, etc.
     RawPointer {
+        /// This is `true` for `*mut _` and `false` for `*const _`.
         mutable: bool,
+        /// The type of the pointee.
         #[serde(rename = "type")]
         type_: Box<Type>,
     },
     /// `&'a mut String`, `&str`, etc.
     BorrowedRef {
+        /// The name of the lifetime of the reference, if provided.
         lifetime: Option<String>,
+        /// This is `true` for `&mut i32` and `false` for `&i32`
         mutable: bool,
+        /// The type of the pointee, e.g. the `i32` in `&'a mut i32`
         #[serde(rename = "type")]
         type_: Box<Type>,
     },
     /// Associated types like `<Type as Trait>::Name` and `T::Item` where
     /// `T: Iterator` or inherent associated types like `Struct::Name`.
     QualifiedPath {
+        /// The name of the associated type in the parent type.
+        ///
+        /// ```ignore (incomplete expresssion)
+        /// <core::array::IntoIter<u32, 42> as Iterator>::Item
+        /// //                                            ^^^^
+        /// ```
         name: String,
+        /// The generic arguments provided to the associated type.
+        ///
+        /// ```ignore (incomplete expression)
+        /// <core::slice::IterMut<'static, u32> as BetterIterator>::Item<'static>
+        /// //                                                          ^^^^^^^^^
+        /// ```
         args: Box<GenericArgs>,
+        /// The type with which this type is associated.
+        ///
+        /// ```ignore (incomplete expression)
+        /// <core::array::IntoIter<u32, 42> as Iterator>::Item
+        /// // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+        /// ```
         self_type: Box<Type>,
         /// `None` iff this is an *inherent* associated type.
         #[serde(rename = "trait")]
@@ -615,34 +1008,47 @@ pub enum Type {
     },
 }
 
+/// A type that has a simple path to it. This is the kind of type of structs, unions, enums, etc.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Path {
+    /// The name of the type as declared, e.g. in
+    ///
+    /// ```rust
+    /// mod foo {
+    ///     struct Bar;
+    /// }
+    /// ```
+    ///
+    /// for `foo::Bar`, this field will be `Bar`.
     pub name: String,
+    /// The ID of the type.
     pub id: Id,
-    /// Generic arguments to the type
-    /// ```test
+    /// Generic arguments to the type.
+    ///
+    /// ```ignore (incomplete expression)
     /// std::borrow::Cow<'static, str>
-    ///                 ^^^^^^^^^^^^^^
-    ///                 |
-    ///                 this part
+    /// //              ^^^^^^^^^^^^^^
     /// ```
     pub args: Option<Box<GenericArgs>>,
 }
 
+/// A type that is a function pointer.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct FunctionPointer {
+    /// The signature of the function.
     pub decl: FnDecl,
     /// Used for Higher-Rank Trait Bounds (HRTBs)
-    /// ```text
-    /// for<'c> fn(val: &'c i32) -> i32
-    /// ^^^^^^^
-    ///       |
-    ///       this part
+    ///
+    /// ```ignore (incomplete expression)
+    ///    for<'c> fn(val: &'c i32) -> i32
+    /// // ^^^^^^^
     /// ```
     pub generic_params: Vec<GenericParamDef>,
+    /// The core properties of the function, such as the ABI it conforms to, whether it's unsafe, etc.
     pub header: Header,
 }
 
+/// The signature of a function.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct FnDecl {
     /// List of argument names and their type.
@@ -650,42 +1056,86 @@ pub struct FnDecl {
     /// Note that not all names will be valid identifiers, as some of
     /// them may be patterns.
     pub inputs: Vec<(String, Type)>,
+    /// The output type, if specified.
     pub output: Option<Type>,
+    /// Whether the function accepts an arbitrary amount of trailing arguments the C way.
+    ///
+    /// ```ignore (incomplete code)
+    /// fn printf(fmt: &str, ...);
+    /// ```
     pub c_variadic: bool,
 }
 
+/// A `trait` declaration.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Trait {
+    /// Whether the trait is marked `auto` and is thus implemented automatically
+    /// for all aplicable types.
     pub is_auto: bool,
+    /// Whether the trait is marked as `unsafe`.
     pub is_unsafe: bool,
+    /// Whether the trait is [object safe](https://doc.rust-lang.org/reference/items/traits.html#object-safety).
     pub is_object_safe: bool,
+    /// Associated [`Item`]s that can/must be implemented by the `impl` blocks.
     pub items: Vec<Id>,
+    /// Information about the type parameters and `where` clauses of the trait.
     pub generics: Generics,
+    /// Constraints that must be met by the implementor of the trait.
     pub bounds: Vec<GenericBound>,
+    /// The implementations of the trait.
     pub implementations: Vec<Id>,
 }
 
+/// A trait alias declaration, e.g. `trait Int = Add + Sub + Mul + Div;`
+///
+/// See [the tracking issue](https://github.com/rust-lang/rust/issues/41517)
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct TraitAlias {
+    /// Information about the type parameters and `where` clauses of the alias.
     pub generics: Generics,
+    /// The bounds that are associated with the alias.
     pub params: Vec<GenericBound>,
 }
 
+/// An `impl` block.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Impl {
+    /// Whether this impl is for an unsafe trait.
     pub is_unsafe: bool,
+    /// Information about the impl’s type parameters and `where` clauses.
     pub generics: Generics,
+    /// The list of the names of all the trait methods that weren't mentioned in this impl but
+    /// were provided by the trait itself.
+    ///
+    /// For example, for this impl of the [`PartialEq`] trait:
+    /// ```rust
+    /// struct Foo;
+    ///
+    /// impl PartialEq for Foo {
+    ///     fn eq(&self, other: &Self) -> bool { todo!() }
+    /// }
+    /// ```
+    /// This field will be `["ne"]`, as it has a default implementation defined for it.
     pub provided_trait_methods: Vec<String>,
+    /// The trait being implemented or `None` if the impl is inherent, which means
+    /// `impl Struct {}` as opposed to `impl Trait for Struct {}`.
     #[serde(rename = "trait")]
     pub trait_: Option<Path>,
+    /// The type that the impl block is for.
     #[serde(rename = "for")]
     pub for_: Type,
+    /// The list of associated items contained in this impl block.
     pub items: Vec<Id>,
+    /// Whether this is a negative impl (e.g. `!Sized` or `!Send`).
     pub negative: bool,
+    /// Whether this is an impl that’s implied by the compiler
+    /// (for autotraits, e.g. `Send` or `Sync`).
     pub synthetic: bool,
+    // FIXME: document this
     pub blanket_impl: Option<Type>,
 }
 
+/// A `use` statement.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub struct Import {
@@ -699,16 +1149,34 @@ pub struct Import {
     /// pub use i32 as my_i32;
     /// ```
     pub id: Option<Id>,
-    /// Whether this import uses a glob: `use source::*;`
+    /// Whether this statement is a wildcard `use`, e.g. `use source::*;`
     pub glob: bool,
 }
 
+/// A procedural macro.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct ProcMacro {
+    /// How this macro is supposed to be called: `foo!()`, `#[foo]` or `#[derive(foo)]`
     pub kind: MacroKind,
+    /// Helper attributes defined by a macro to be used inside it.
+    ///
+    /// Defined only for attribute & derive macros.
+    ///
+    /// E.g. the [`Default`] derive macro defines a `#[default]` helper attribute so that one can
+    /// do:
+    ///
+    /// ```rust
+    /// #[derive(Default)]
+    /// enum Option<T> {
+    ///     #[default]
+    ///     None,
+    ///     Some(T),
+    /// }
+    /// ```
     pub helpers: Vec<String>,
 }
 
+/// The way a [`ProcMacro`] is declared to be used.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum MacroKind {
@@ -720,30 +1188,36 @@ pub enum MacroKind {
     Derive,
 }
 
+/// A type alias declaration, e.g. `type Pig = std::borrow::Cow<'static, str>;`
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct TypeAlias {
+    /// The type referred to by this alias.
     #[serde(rename = "type")]
     pub type_: Type,
+    /// Information about the type parameters and `where` clauses of the alias.
     pub generics: Generics,
 }
 
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
-pub struct OpaqueTy {
-    pub bounds: Vec<GenericBound>,
-    pub generics: Generics,
-}
-
+/// A `static` declaration.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Static {
+    /// The type of the static.
     #[serde(rename = "type")]
     pub type_: Type,
+    /// This is `true` for mutable statics, declared as `static mut X: T = f();`
     pub mutable: bool,
+    /// The stringified expression for the initial value.
+    ///
+    /// It's not guaranteed that it'll match the actual source code for the initial value.
     pub expr: String,
 }
 
+/// A primitive type declaration. Declarations of this kind can only come from the core library.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Primitive {
+    /// The name of the type.
     pub name: String,
+    /// The implementations, inherent and of traits, on the primitive type.
     pub impls: Vec<Id>,
 }
 
diff --git a/src/stage0 b/src/stage0
index f36010fa4b4..dcc22673f13 100644
--- a/src/stage0
+++ b/src/stage0
@@ -14,434 +14,448 @@ nightly_branch=master
 # All changes below this comment will be overridden the next time the
 # tool is executed.
             
-compiler_date=2024-06-11
+compiler_date=2024-07-26
 compiler_version=beta
-rustfmt_date=2024-06-11
+rustfmt_date=2024-07-30
 rustfmt_version=nightly
 
-dist/2024-06-11/rustc-beta-x86_64-unknown-freebsd.tar.gz=4bf5a3ae2656a992beedec2f41dc98c791426a1a6a88f3503b003b4d6f0ddc1f
-dist/2024-06-11/rustc-beta-x86_64-unknown-freebsd.tar.xz=feaa1484586e78d77225734328d460277dde14baaf1299a30b30ef91e9a26a82
-dist/2024-06-11/rustc-beta-x86_64-unknown-illumos.tar.gz=9c692a71916f7ca9d41a97416f51d463b0495311491ba92b4d3cdb0f6c4e7c87
-dist/2024-06-11/rustc-beta-x86_64-unknown-illumos.tar.xz=97dece0cc2e4856a49f9ae17f09171fb55f140987acd0f988bbd0aa1e8971936
-dist/2024-06-11/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz=6ad2e87e637302e8458d47dc1af923e38bffd7332775cfa5520c29110594d9b9
-dist/2024-06-11/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz=84f6755c1377ced8ed2700b5ca9a2d38dd2e26a03e1fd636841ad46d3cf63895
-dist/2024-06-11/rustc-beta-i686-unknown-linux-gnu.tar.gz=11b439045379be2722cb42409b8bc342ff4b5f7df85e42566006cd72bb1a4e8a
-dist/2024-06-11/rustc-beta-i686-unknown-linux-gnu.tar.xz=4e5103702b4e43ea71914e9c508aeb0db6382ea331c31981142163b2a89e19e1
-dist/2024-06-11/rustc-beta-powerpc-unknown-linux-gnu.tar.gz=396a3aaefca9511086f7e5442209b70622082d133b96783b4237c3f01f42bf87
-dist/2024-06-11/rustc-beta-powerpc-unknown-linux-gnu.tar.xz=66e46ed344af9f165b7c4fde2c576340fa81ecade61c45ecc1562de70a9203da
-dist/2024-06-11/rustc-beta-aarch64-unknown-linux-gnu.tar.gz=831420b262c5a2f44459e0daceebe271f298179c37aa5b7a1704a15bbbb1fb97
-dist/2024-06-11/rustc-beta-aarch64-unknown-linux-gnu.tar.xz=691a6c4d0276add72cfab40968520ff48f683d4e660a50d1626ba9564dbf4914
-dist/2024-06-11/rustc-beta-aarch64-unknown-linux-musl.tar.gz=ebe1efe3c5d74e37d1c40dbd585ada7a7e256ce76911746f54994dfa15f9907f
-dist/2024-06-11/rustc-beta-aarch64-unknown-linux-musl.tar.xz=3bb37fcab069713fe8aa5ca72291a439eba5af4a3cc0be9d152e5f29ccaef864
-dist/2024-06-11/rustc-beta-s390x-unknown-linux-gnu.tar.gz=c00c2ecb5aae552069395d03f4135f051da073efc68ed645348f026c1884799b
-dist/2024-06-11/rustc-beta-s390x-unknown-linux-gnu.tar.xz=2c72347688058091a4bcb0c2fbcff49020df2b2c1733bc19d93b6e5149d5b13a
-dist/2024-06-11/rustc-beta-aarch64-pc-windows-msvc.tar.gz=517977edaa51470d460aa9ec09309eea2082cffa6adb13571a8f36efa9351dff
-dist/2024-06-11/rustc-beta-aarch64-pc-windows-msvc.tar.xz=0cc0b740cb267fde814b4971591b5797faa528b1e6250ef7b2d5220f0916208d
-dist/2024-06-11/rustc-beta-x86_64-pc-windows-gnu.tar.gz=9fe7d85fdbca12fbfdb776789c336f726303c8845a6f6c93b2dc6ea8487585d4
-dist/2024-06-11/rustc-beta-x86_64-pc-windows-gnu.tar.xz=38130e3d9779ad54bd890c4001b34b7c58368ed1940e7e676947e9c05a8f6649
-dist/2024-06-11/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz=acca3e045de3c0d908caec4249e3905d207d96b4a1722644457b3cbe5707422c
-dist/2024-06-11/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz=e4e92fc4b672f72b1f03db62ae712d9f944b982db89cf0d8dcb94adb1d560b3e
-dist/2024-06-11/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz=63274e707bd0d2b2f08c49f170f26773f802db833347d2aa694d345d11c841f5
-dist/2024-06-11/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz=13702b24228d983710d5678e0a1003e4f77e2244fbdf599015f52adbbb77bfcc
-dist/2024-06-11/rustc-beta-x86_64-pc-windows-msvc.tar.gz=ca877491bf7bf50989b9ac21c12e335fd0ff002ccf4a2c07316ae1df1a3d7e6b
-dist/2024-06-11/rustc-beta-x86_64-pc-windows-msvc.tar.xz=d757a328595887039d8017e9e3faf79448850c3dd9bd3c26d309a313ccc09a38
-dist/2024-06-11/rustc-beta-x86_64-unknown-linux-musl.tar.gz=155497f2abe036f09f6aa014969d58132a9e2e4e148fea485b483e0dc3705a39
-dist/2024-06-11/rustc-beta-x86_64-unknown-linux-musl.tar.xz=6204d1fa08beeadcf1564e334cbb65a7317c571557cbc5517eb6bf08f5b0ce75
-dist/2024-06-11/rustc-beta-aarch64-apple-darwin.tar.gz=3bd7db536344c6a3d0d0bdf95986136d5db8996228802444b561783f2e7c3c9c
-dist/2024-06-11/rustc-beta-aarch64-apple-darwin.tar.xz=b425561b3e7d9130fae94e78522bb262c634304ced32030828743fb332b11ecb
-dist/2024-06-11/rustc-beta-x86_64-unknown-linux-gnu.tar.gz=e2f78198d33f98aa34bedd4f5920868a8f68620e29eca2917833f6a8f23f787c
-dist/2024-06-11/rustc-beta-x86_64-unknown-linux-gnu.tar.xz=22f3b45678081fe52a9c8e89234a9939aad5623eb43ec54921effc28c0bdcd80
-dist/2024-06-11/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz=beb5ec95069cbac4e53c51ea3e785ab5f25122132c8b78b196372bb2a31ed46f
-dist/2024-06-11/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz=17242f74c96cf581f2e40a82f6d7fbd585af2c2990cc73ad4ba7a3503dd279a3
-dist/2024-06-11/rustc-beta-x86_64-apple-darwin.tar.gz=d952d90397c70c5b53caa98b2e5d48e35780e1e5b342775c10fcbf504717d2ec
-dist/2024-06-11/rustc-beta-x86_64-apple-darwin.tar.xz=14bd4336eb396a133ddbb2acd01ae799f2f68a7ac723a00a9db8c3e06bfa8027
-dist/2024-06-11/rustc-beta-loongarch64-unknown-linux-gnu.tar.gz=a2118f80091d62ebb762df0bdd159d19befb440d754034da7348aae50d63628f
-dist/2024-06-11/rustc-beta-loongarch64-unknown-linux-gnu.tar.xz=a4b9d1a04d8f9cfd4daaf57fbeed3615d000c5107c6fa1b2992dad6ca552e35a
-dist/2024-06-11/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz=d5c16c5621e43cd3007ba4d2bc0f6e8a3a2376bc2a911e42bd2f2670ff94c12c
-dist/2024-06-11/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz=202662492afd863b6b6428a3bc5ed822c62ac2aeb8a0264df1d69cc5a3728d8f
-dist/2024-06-11/rustc-beta-i686-pc-windows-msvc.tar.gz=a9fb64cac53595444bdbe8f152e52214812498e0c6e2b664db10f1f693a92dca
-dist/2024-06-11/rustc-beta-i686-pc-windows-msvc.tar.xz=fe78c5ac51d96c3c3e222828dca3d105a2d4d7f8acd6e0d86ecd4b27ea70a4c3
-dist/2024-06-11/rustc-beta-arm-unknown-linux-gnueabi.tar.gz=8c584010c964ef1b02e1014ca1c6ed9584c1ff781f8af115ee001e3a13213954
-dist/2024-06-11/rustc-beta-arm-unknown-linux-gnueabi.tar.xz=4a407fb59db284ddf6fc0ccd487116fafbcd7c227f3dfd4e0b7b64dd560dc113
-dist/2024-06-11/rustc-beta-x86_64-unknown-netbsd.tar.gz=2f07a283bb0e57ad50366b67d216503a423867eae205e4354b74b748e9d3ce85
-dist/2024-06-11/rustc-beta-x86_64-unknown-netbsd.tar.xz=8008331b32e9d0daeb275327082e38671dcc91864a3ac95be67bd15ecaa852ad
-dist/2024-06-11/rustc-beta-i686-pc-windows-gnu.tar.gz=c42637a8aa8666d746a45c9f47b437a9720d355b5bc6db42c2a90fb03d2c4a26
-dist/2024-06-11/rustc-beta-i686-pc-windows-gnu.tar.xz=eabe3a7e72829e0e5904ef381157cc3da169d9f5942e0367b2d1b1781c387560
-dist/2024-06-11/rust-std-beta-x86_64-unknown-linux-musl.tar.gz=f4010eea815cbab895c96311a456c4e3aa24c5f0d55f09052bcde59de7f286e6
-dist/2024-06-11/rust-std-beta-x86_64-unknown-linux-musl.tar.xz=a8f555c713cbe4a1860ee5bc812eb624f2775e034da54bd0e37c325453d70448
-dist/2024-06-11/rust-std-beta-aarch64-unknown-linux-musl.tar.gz=c89619ed4ec28d4f48ef2f7e51155716483a7f4bb51fe38235e69d4694cfcbe5
-dist/2024-06-11/rust-std-beta-aarch64-unknown-linux-musl.tar.xz=89aa3d1add14298bd40e3bcbc6b41df91312258ac6f203fff9eca4422f0c5e9f
-dist/2024-06-11/rust-std-beta-x86_64-apple-darwin.tar.gz=2303e7926bcc4fa2c67c7063fcac3a7b581fdd91fb89123cb6cdf514ff38afed
-dist/2024-06-11/rust-std-beta-x86_64-apple-darwin.tar.xz=9ddf392d8c696e902c2924ff938a4bd099b9a54834dc62710e42527e464e776f
-dist/2024-06-11/rust-std-beta-x86_64-pc-windows-msvc.tar.gz=6016b465a0cfc628f2c978ed18bc19a4a27e20a5ac11a170c40d01a857a5f50a
-dist/2024-06-11/rust-std-beta-x86_64-pc-windows-msvc.tar.xz=8e3d6f7ef6efead7d08b1c889bcc6e520d0a6d29226ade1b150aeb625fdb9abd
-dist/2024-06-11/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz=5f53b7630fa7703fc6752c3fb8c8eba8e25b9f77a3b91e14982510a0091d9e44
-dist/2024-06-11/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz=8ed3c2f0b0f81d197d0dbd01aa777eb17ebc7303176601be2b2b05ebe1bcc971
-dist/2024-06-11/rust-std-beta-loongarch64-unknown-none-softfloat.tar.gz=dbc1a1bb8cfb4472739d7f3a52bcd571357d2d2761f3723aa4c7d69abe9a5dfc
-dist/2024-06-11/rust-std-beta-loongarch64-unknown-none-softfloat.tar.xz=58f46f20d58669d497ff683d6ea85e18ff68d51a442f6e21bc20ddee779e1c4f
-dist/2024-06-11/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz=d71947b5ddcfe538162b14d6b785c365c34f2b6ac2f1abdc90b020c4a446a313
-dist/2024-06-11/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz=ca0a665e566b3ff74c5f552e7e4e030d3cae9080dbb6055dce3aa41206b5b111
-dist/2024-06-11/rust-std-beta-x86_64-unknown-fuchsia.tar.gz=e927c0890d2c5135d86b1960b6b182d5c47853b53eeb196b4748e7b8ec9362e4
-dist/2024-06-11/rust-std-beta-x86_64-unknown-fuchsia.tar.xz=df33672f826ce8681d6c18ec2129ef47623b7cbaf6515cd921d39dfc05cb7a06
-dist/2024-06-11/rust-std-beta-i686-linux-android.tar.gz=2559fdcf250e7e0a1b5589e8f2bc69340f5610b7e6ddf08185936fa2e6f10534
-dist/2024-06-11/rust-std-beta-i686-linux-android.tar.xz=442f0aa53f343eec2b6984934bbf0651ff45f314d1f46dad2aa11a2f5c5a5a5b
-dist/2024-06-11/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz=cb657852d05766e1c18b11d99a94f3570b6c6147dbf9b2113b80236566d2d4ac
-dist/2024-06-11/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz=943de72c556821b67d59afd9dd128bfb01b3ba743dd3e7561c50559afd3768f4
-dist/2024-06-11/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz=a7c6d3f54d925be073007e3737173b0def7d781b6bfd5345971a69300aeee9c3
-dist/2024-06-11/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz=cb9115328bf6f5ae661ce5bc9cc9165c6c9e6f759f3cc5038154531b314e6013
-dist/2024-06-11/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz=2a2dac9fba84958818f6b31f30f91fcfef521111827937c88aa696b646f5b075
-dist/2024-06-11/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz=d16b28da0196a815f028d432dfa0957d0bfb512b259129969548bd050afac872
-dist/2024-06-11/rust-std-beta-armv7a-none-eabi.tar.gz=d78f96102490f9025598b11cb72e31e96d3f5fd566e8f7b2b2c503a37b0dc6c3
-dist/2024-06-11/rust-std-beta-armv7a-none-eabi.tar.xz=a439af58e90970b4dadaa04d8f94ea53c6c7a159117926c46b7da0eaa0d0ca5b
-dist/2024-06-11/rust-std-beta-i686-pc-windows-msvc.tar.gz=d7847f3d9b1a2f50541ef3d2c25eeda469b28412817cadca52756aeb4f2c57b1
-dist/2024-06-11/rust-std-beta-i686-pc-windows-msvc.tar.xz=622cafc347ec1d3f0ef70354a0713cd255029730b17ad1f1ee951d9b0cb515e5
-dist/2024-06-11/rust-std-beta-x86_64-pc-windows-gnullvm.tar.gz=5fee2542ee8ee8d155edc0ac36ec8822896e6f93f9f573b9284d70aeb186a05d
-dist/2024-06-11/rust-std-beta-x86_64-pc-windows-gnullvm.tar.xz=dfe9ca3e3f217922b65db0d65826c0962369fefd3d5d72d6f03039acd710f122
-dist/2024-06-11/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz=b0937c5dcd458f313aabe07668ea338f2629bfc9c45d6139211b6923a7c7eb0e
-dist/2024-06-11/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz=65973a26c69f8ca7d3022180e2729161f7a618706cd9974fc54b14cf48f1af79
-dist/2024-06-11/rust-std-beta-aarch64-unknown-none.tar.gz=def2fc3aca20a74d023156606067f88ea8f1c8b602fb628b8f27ee43e3b62cfd
-dist/2024-06-11/rust-std-beta-aarch64-unknown-none.tar.xz=43cdb54af35a6c00ee10759a3f6ff6ca5c9080ba817aaf2eab7df8f239d77196
-dist/2024-06-11/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz=ae2cbe53d304442e112585dd968f72454cc33bb75d3b4d7854a04575ff7b5301
-dist/2024-06-11/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz=b3192290a45ff978126f4f08e7ddaf6de8720a2f6abbc5b41536fad6f994d7ae
-dist/2024-06-11/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz=0e2dc167dbb66366252100fc87b94a67cca3360343302697c2989beb2eb14704
-dist/2024-06-11/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz=6144604269f533eed11471b4c5d2f31a9f8340d9edf0f398a42e6e970c95b991
-dist/2024-06-11/rust-std-beta-riscv32i-unknown-none-elf.tar.gz=b57e11248924ac54500d80525b8fe823e7dc74bc579c2b7f3f076c0a4c85ee2a
-dist/2024-06-11/rust-std-beta-riscv32i-unknown-none-elf.tar.xz=9e473a5de0d02e6d8278a9e2430af135e3d6d4ecf5ce59827b384c8f20af39c2
-dist/2024-06-11/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz=1a62b5af52767e68146a45a47384b33c93b32a4579e51d41f66746e38dfa6eba
-dist/2024-06-11/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz=81bcf448ec54470edf60c2079ad9ef03f34052aef5fe9d8f5af933c565fdfd29
-dist/2024-06-11/rust-std-beta-x86_64-pc-windows-gnu.tar.gz=88eb49f86265a7fdb49b455cf5a9a373ac1e0f7cbcac08ef2194eaefbb039b22
-dist/2024-06-11/rust-std-beta-x86_64-pc-windows-gnu.tar.xz=bf9a278615765e199786d16f154006007ddfca0d5a5869c55a05e513a7b06580
-dist/2024-06-11/rust-std-beta-thumbv7em-none-eabihf.tar.gz=13f16402dea66facba6e10a9556e0afdbd6b004e8aa5d08e106cf76ea59b8288
-dist/2024-06-11/rust-std-beta-thumbv7em-none-eabihf.tar.xz=7ecd66dc65758cdf32cdebc38f6f399392788a7085d69ec7e8fbd63be7b3e904
-dist/2024-06-11/rust-std-beta-aarch64-pc-windows-gnullvm.tar.gz=96ccb2252defcd5bcd9eca19380b9d4e4115ffb135efebe6717b1527ee440bf8
-dist/2024-06-11/rust-std-beta-aarch64-pc-windows-gnullvm.tar.xz=c31f4ef95857a445bc480b73babb886e259443b3137efd694c4b67f913838212
-dist/2024-06-11/rust-std-beta-thumbv7em-none-eabi.tar.gz=0637fe1ab1284334ed4f9aec87a4b51b6983418997844e10ffe20326078f6d18
-dist/2024-06-11/rust-std-beta-thumbv7em-none-eabi.tar.xz=ac7f13ba1a107d03c1b7bb0d2e6753b926a26554c82de38263113e2d5dfeca21
-dist/2024-06-11/rust-std-beta-s390x-unknown-linux-gnu.tar.gz=0e8a21970d4ea6331968b10e990cb6dbe3d38af393e4dc8d603efec1b59aa0bd
-dist/2024-06-11/rust-std-beta-s390x-unknown-linux-gnu.tar.xz=04b9663cef2d3507c96b77b18aff7c9beee0f6bd0e0cb9ef37b8c9cacadbb198
-dist/2024-06-11/rust-std-beta-wasm32-unknown-emscripten.tar.gz=01d4da0efebf4615da7c92c6cfdaedaf283d3f5e66c58a1b1e2e17488d86b3d3
-dist/2024-06-11/rust-std-beta-wasm32-unknown-emscripten.tar.xz=c203ec9216407f90d0bcc451e40a29e50279dae8ee161f05d9245e3cc8e1b30a
-dist/2024-06-11/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz=3621e0a16f7e6d9f292894a343941399a54b5d76a858fe5a69b83c95f15ada07
-dist/2024-06-11/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz=5944208b88c6924f8586304abea6827cdf756066158dc64200e207027143e843
-dist/2024-06-11/rust-std-beta-aarch64-unknown-uefi.tar.gz=1887e342d5c6453a63336023e51c124838762f89e9289d1abd8226a717bb96d3
-dist/2024-06-11/rust-std-beta-aarch64-unknown-uefi.tar.xz=ba0ca831ed66a72a14c8c9dd591e97d7d6cbc55762c961283088e897de4a8669
-dist/2024-06-11/rust-std-beta-aarch64-unknown-fuchsia.tar.gz=59790fb6982ebfefc40d352d411604840b7540a6ddfb26ad14d70e139df3ab99
-dist/2024-06-11/rust-std-beta-aarch64-unknown-fuchsia.tar.xz=c022c80da2debecdbea32ce34ef040bdebc8566a78e2867512815532746e1c95
-dist/2024-06-11/rust-std-beta-armebv7r-none-eabihf.tar.gz=4d4a380bed233e86ea957c173412b819fce00d66d369657a0778da5e4f244034
-dist/2024-06-11/rust-std-beta-armebv7r-none-eabihf.tar.xz=577763a4758c42bcf0c875d606a6dd538c07866e9a65c2b73271f0e9d0762830
-dist/2024-06-11/rust-std-beta-i586-unknown-linux-gnu.tar.gz=29f8e4dc5d88bfd66f600402022267ad85d4afcffd7142107d0fd28d0cae4cd8
-dist/2024-06-11/rust-std-beta-i586-unknown-linux-gnu.tar.xz=d030db59dd1788fa8438c52b9a8cbc6754eaf529de60fa4fa9693a687e644dfb
-dist/2024-06-11/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz=df978c1519ea4b50fcec2ec18d2cd9a6b813982dc50f6442af9ce340b98a8c46
-dist/2024-06-11/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz=13585b56ce162922dbf03d0b6432a6af9b9059a664063a6adca957301c23b905
-dist/2024-06-11/rust-std-beta-wasm32-unknown-unknown.tar.gz=6365c96d363a345c4882ad47a3e9242f37c930a10bdc89d137e5e05b1b599351
-dist/2024-06-11/rust-std-beta-wasm32-unknown-unknown.tar.xz=480e07d3f110ff9f201315f5a01bf674ead911773241d80d9005772cfe4a3d88
-dist/2024-06-11/rust-std-beta-armv7r-none-eabi.tar.gz=0514e7022540078895be3000fa0405157bf1165762e77672f78230e62ef2c8ec
-dist/2024-06-11/rust-std-beta-armv7r-none-eabi.tar.xz=659cec4d3e3f0783bf9a8b42a245b995e00b36a8ff04a9b6b458ace016d825d1
-dist/2024-06-11/rust-std-beta-i686-pc-windows-gnu.tar.gz=2c6b17e0fa22a9d528217fdb8231aefd21839e29babad0fd975fd3654a9706f2
-dist/2024-06-11/rust-std-beta-i686-pc-windows-gnu.tar.xz=c2c98b0c6b21618d5c49283f19ccdd3ba76159afd904c9683251d36317582615
-dist/2024-06-11/rust-std-beta-x86_64-pc-solaris.tar.gz=9433aed1f5f87157cf02d13e7ad375e9a2e9a260afb8419a05eeb1856069ab26
-dist/2024-06-11/rust-std-beta-x86_64-pc-solaris.tar.xz=2a39a792676fd60f47db90979fd56f3fee709d05d91b5c8bf4e0a01f39fed14e
-dist/2024-06-11/rust-std-beta-x86_64-unknown-linux-ohos.tar.gz=29e4553e9889c3e202f550042555b5c24cf52ce68979870fe33d9e9eaad37db0
-dist/2024-06-11/rust-std-beta-x86_64-unknown-linux-ohos.tar.xz=7d56ef2eb64550f95b2ec1e1cfb9f153e9c6b412dcceef35f76db44eccd4d8a1
-dist/2024-06-11/rust-std-beta-i586-pc-windows-msvc.tar.gz=da7c08348c6834793263e136747e0e3dfcd5cd805c0c6ca25323fab8a30de427
-dist/2024-06-11/rust-std-beta-i586-pc-windows-msvc.tar.xz=3d60ea1671800cb8f271f1869186ed099f35ee8171d23df7c6ef0c79b4567540
-dist/2024-06-11/rust-std-beta-riscv32im-unknown-none-elf.tar.gz=f3cfa8625f3586ddf48c301b7016d49d216324daaa3b76168a97f15506346c3a
-dist/2024-06-11/rust-std-beta-riscv32im-unknown-none-elf.tar.xz=2e5388097f10a3640514d1a4040f6fec090e1c4aba0259cbdd900ead7fcdfd94
-dist/2024-06-11/rust-std-beta-i686-unknown-freebsd.tar.gz=cf38eeced5efe6139043e123b217a5c3f43bef3d86001a9a51fa21b012c9b468
-dist/2024-06-11/rust-std-beta-i686-unknown-freebsd.tar.xz=e078625da24308d78603400e96454e60606bed23f1132b64efbbbc815791d58c
-dist/2024-06-11/rust-std-beta-aarch64-apple-ios.tar.gz=2f1dcaa67df6adacbb850bf17ed5df8258fd2087668d028814874fc8292bf420
-dist/2024-06-11/rust-std-beta-aarch64-apple-ios.tar.xz=2a11e0abb8b162a12f72825cac59cc0df993b5582d911bdf6b97252078887651
-dist/2024-06-11/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz=d7f4366df7f3599f031b9654d3c0bebd9c21ec530330283e6560cceccc17365b
-dist/2024-06-11/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz=cb9e8470fd9934870cbb881f7611a0bd614416faa42cfa6096a1ed19abdf9cac
-dist/2024-06-11/rust-std-beta-wasm32-wasi.tar.gz=5e7d7b535a7c1449a4dcac4022de279c7676852a7da3e63dc063595dd3fa1b54
-dist/2024-06-11/rust-std-beta-wasm32-wasi.tar.xz=c4db5ad4aa261a01ba3fd8a191c7ac6323e6134b2e17522b3fe0891a642d4c87
-dist/2024-06-11/rust-std-beta-x86_64-apple-ios.tar.gz=a27f3ff22b233c72673e32bf257f766ad8e11abfaf9f83fc7c3e756f785ee83e
-dist/2024-06-11/rust-std-beta-x86_64-apple-ios.tar.xz=8592a2f8b1d6c3cab199cabe8b6e9a668b90bd77bf6a5e0869e2b4f3cc6d1170
-dist/2024-06-11/rust-std-beta-riscv32imafc-unknown-none-elf.tar.gz=ffd9d5acd9a2a33e6a699b850d1776521da443b52504ba77fc71d6dd7353e18d
-dist/2024-06-11/rust-std-beta-riscv32imafc-unknown-none-elf.tar.xz=e92eec9cd55b37f135237c98cfe00c4ee23d2ef400cc3470deb8f1a0010e94c3
-dist/2024-06-11/rust-std-beta-x86_64-unknown-illumos.tar.gz=b1d2e427120295375eecc3d8fc647fe57e1195210d7d0243b20d156f173c3155
-dist/2024-06-11/rust-std-beta-x86_64-unknown-illumos.tar.xz=b97fe83bb5050460465c57c37456868368d0ce18e5134fedad07ae00df8b7432
-dist/2024-06-11/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz=25ad2d1a91456394427a5db691ebd903e56e60daa89d73598155655caf6592b6
-dist/2024-06-11/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz=88b0a7fb002922f78af0f8e9580acdfeb4c341c9fad35e53daf4d6073c73ab8f
-dist/2024-06-11/rust-std-beta-x86_64-unknown-netbsd.tar.gz=b5e129c655bdc051eaa5aca8c8a577914100137a5bca753df619edd22889a1c2
-dist/2024-06-11/rust-std-beta-x86_64-unknown-netbsd.tar.xz=5fc42453c00c3498af2fd60fa4345c2047f302113666bf4a1d044539e3c1e66d
-dist/2024-06-11/rust-std-beta-thumbv8m.main-none-eabi.tar.gz=afb1e9e37af72ba42b71f2a8a78ef7ba8593dbf8e35501e20a81e2aae204722e
-dist/2024-06-11/rust-std-beta-thumbv8m.main-none-eabi.tar.xz=3b7f63b544a5e8aad8a18097b915e01c1fb880d48514bd1fefe3a5d4872eae28
-dist/2024-06-11/rust-std-beta-arm-unknown-linux-musleabi.tar.gz=bc151debda651b76573e77c489c3b9c2be4af0f632e0061e067889f21ab254fb
-dist/2024-06-11/rust-std-beta-arm-unknown-linux-musleabi.tar.xz=f2f9225460e2e7fa7d28cee2dfdab483698c6f51b0eeafe49e2d8e44381a727c
-dist/2024-06-11/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz=5418a327d270c603ddc903ae6061fcb6bc9bca14593f13fe10ab3fe0f4a656ca
-dist/2024-06-11/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz=423e7f6fd6555c6d850e7317a8677d4778bc1270d3cfefc05614ef1acc61fd96
-dist/2024-06-11/rust-std-beta-thumbv8m.base-none-eabi.tar.gz=d30d36a72c1e874a7f9df7f805f5cea3617f912b5ad5e7163616b07022e0f7ae
-dist/2024-06-11/rust-std-beta-thumbv8m.base-none-eabi.tar.xz=4afd0b4ab3787dcbb2b2f686d56844c6aa3af69fbd72d04bd57901fdd58b6333
-dist/2024-06-11/rust-std-beta-loongarch64-unknown-linux-gnu.tar.gz=0a9b8bd1d39d346a20803ede808815dbf0cd55d9167561c8aabe7db3300a3dda
-dist/2024-06-11/rust-std-beta-loongarch64-unknown-linux-gnu.tar.xz=e36372611dd3cdabd1f32fb942c79bd31b5fc13946448cbf9a178ad5005dc7b5
-dist/2024-06-11/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz=2fe6221704614b167d837f52cfd439d9586e27ae82a34577659f86382c3192fe
-dist/2024-06-11/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz=55ffdc97b8b6d309b1aa8443b49a5fd6133f5d7653069eb7f32625c1c0bf86ea
-dist/2024-06-11/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz=87386371b64d4d922dc2fd01a0db28191748002b74a59437ddbab572b0d6fce5
-dist/2024-06-11/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz=6c1f9a6683a9d3ad8203b9d08ed829e4990675cb07fdc2214fc1f7970dee7e60
-dist/2024-06-11/rust-std-beta-nvptx64-nvidia-cuda.tar.gz=525a64f28aa0d757e82558737db3150ff90ecb885c3da8e0215370e47fb2ff23
-dist/2024-06-11/rust-std-beta-nvptx64-nvidia-cuda.tar.xz=af49d1730949036a48c05a147a3c67885326df5bea314fef2828e04433f33ef0
-dist/2024-06-11/rust-std-beta-armebv7r-none-eabi.tar.gz=eba00bc621ee0235444698e5bc67780bc93765e70bed11634a8555d8d645635b
-dist/2024-06-11/rust-std-beta-armebv7r-none-eabi.tar.xz=236fe5262d76fd8ab7c12ab6c231608c7e704e5fc0d95210b47e0c86201d8a8d
-dist/2024-06-11/rust-std-beta-aarch64-pc-windows-msvc.tar.gz=ac98cc34543e6faa0429cb9756d1b0d30dc13d8d8a44380b5feecc0e7d083e40
-dist/2024-06-11/rust-std-beta-aarch64-pc-windows-msvc.tar.xz=ed8fffbe7899a7c35e5985adae1b35b7eabd076970a8eac280e834b7877f272c
-dist/2024-06-11/rust-std-beta-x86_64-linux-android.tar.gz=fa53ef5ea66f93f9fa46ac84d3cf6a16743b46a941910b092c9c71208a15defd
-dist/2024-06-11/rust-std-beta-x86_64-linux-android.tar.xz=66b394876549c4faaf872d4103ee49ef59cfba5c78777c01ad1df00dc6babd14
-dist/2024-06-11/rust-std-beta-sparcv9-sun-solaris.tar.gz=63794d1cc16a541cc07b56870d86db2212c2c8e3f06e11fd9bdca90fd93aa56f
-dist/2024-06-11/rust-std-beta-sparcv9-sun-solaris.tar.xz=4d419a3c4402c303b9437c7564e2bea79575623eaa0b300c2fe688d9d8f9db95
-dist/2024-06-11/rust-std-beta-aarch64-linux-android.tar.gz=b82186abf1bb250753a2640def13aa477b606e0601c5c1fdb25af0e37ea638b0
-dist/2024-06-11/rust-std-beta-aarch64-linux-android.tar.xz=57065c7b4f1f5d51d1366164b62b4114ab95f1a68cf551d12db8e9a2dad044dd
-dist/2024-06-11/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz=bef7ed6391f906226a20f8d2d842fbc335891d7fb92f91b1c5873ce778d70675
-dist/2024-06-11/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz=d80843f5f25923605681541b285ebf6868c0368841efacd376aac4dc9f01d0ce
-dist/2024-06-11/rust-std-beta-armv7r-none-eabihf.tar.gz=5b7d75f5f9294327ffb3c441b2e99fbc8402d1dfe0afaa20b2981a987e96801b
-dist/2024-06-11/rust-std-beta-armv7r-none-eabihf.tar.xz=ab56542b3be354d6c4f19fefe90af2daf59507e969a4144b6553a900e37e2a4e
-dist/2024-06-11/rust-std-beta-armv7-unknown-linux-ohos.tar.gz=7365d0ccde4cd000b44992c80cf0e48ead99c2a00e18cde4446d9401792606a3
-dist/2024-06-11/rust-std-beta-armv7-unknown-linux-ohos.tar.xz=69124687ee3ff876f557b7b21c8f78f7015c5f3b6537b65480613469772e00ec
-dist/2024-06-11/rust-std-beta-i686-pc-windows-gnullvm.tar.gz=d1307c1b3fab3dcb6b1e5cfd5c30e1ef1c7b7e1e831ccecb00ce35bc2c1d8b9c
-dist/2024-06-11/rust-std-beta-i686-pc-windows-gnullvm.tar.xz=8685907906feb9e16e34d4ea72e3ad338df9d6407dca6da81739b100926efcd2
-dist/2024-06-11/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz=d8c1c3d800eaedcf23c25f436e30892df1938a618200f0f041fc1921a5b517ac
-dist/2024-06-11/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz=53493d039721d5a2f54eb49ba7e16a205dd846bee559519182ca0af30111d182
-dist/2024-06-11/rust-std-beta-x86_64-unknown-redox.tar.gz=3f9842f81f45cbf35fd923ea69f1c88696070edfec0dcecac286519820741078
-dist/2024-06-11/rust-std-beta-x86_64-unknown-redox.tar.xz=73bc6b9b72bf6a9ba7dabe63b7a7d426eb47716466000d05802ef78ccb9128e4
-dist/2024-06-11/rust-std-beta-i686-unknown-uefi.tar.gz=c9954b477c329c3706891f77e9163d98aeadd96b1aa8a71f1eac20f316a9269f
-dist/2024-06-11/rust-std-beta-i686-unknown-uefi.tar.xz=88876cb6cf03707065fe172540e82faaf5dd55332c939891253476d4da3f8a00
-dist/2024-06-11/rust-std-beta-aarch64-unknown-linux-ohos.tar.gz=e731faa24568e97821c5960229dd9a489ea7ead964a5aa052a6db322bcc55c18
-dist/2024-06-11/rust-std-beta-aarch64-unknown-linux-ohos.tar.xz=47b529a6e19c9d609c41809fd62906c34f23a5c515bf62d91e88a87cf7cc0c85
-dist/2024-06-11/rust-std-beta-loongarch64-unknown-none.tar.gz=c6150b3b7481f2396b305188a16c4ce2206c440e9d7639446c76566d00dc5159
-dist/2024-06-11/rust-std-beta-loongarch64-unknown-none.tar.xz=e641747ef4ae46e4d0a8a3050d00b1b8c21c0f25da53a54de8e540a9953468db
-dist/2024-06-11/rust-std-beta-wasm32-wasip1-threads.tar.gz=37d141ba5beeaefd08834154f66219df734c379c9315c094433aebb75b82bca7
-dist/2024-06-11/rust-std-beta-wasm32-wasip1-threads.tar.xz=2045a0b765de96eb17e18d8028ed2e553cc998fb71a4811e3d848db320f6b9a3
-dist/2024-06-11/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz=82de12e6a2b01c0b98c83b4264a4e00ceefc424f673c97826bb28729c3f31382
-dist/2024-06-11/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz=c97b8a57ed8eefd60bbfe2df54121c548d9e271d9691def843185bac9d82b703
-dist/2024-06-11/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz=6903175fa7cc3fdda5545ce11f4cc504e4183e56c626e25ff2b0d20a4f5190c4
-dist/2024-06-11/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz=df06eee91ba57ff2c0a779da5d746db02f682514b8c03de875f03c96d05188e5
-dist/2024-06-11/rust-std-beta-thumbv7m-none-eabi.tar.gz=d7023edb8c723803e114e5b8ed316a6839e0c37d92cf6a2a09b767ee5ea2b7b9
-dist/2024-06-11/rust-std-beta-thumbv7m-none-eabi.tar.xz=41e19659bc0e0445ebafc49740579f0ac23a9af8e233c529ba2132f3d111faa9
-dist/2024-06-11/rust-std-beta-arm-linux-androideabi.tar.gz=42c0a6bfed8ca53b8833dbee78f2eab92bee061c42a4d629e870c8e655bc3728
-dist/2024-06-11/rust-std-beta-arm-linux-androideabi.tar.xz=5f85c99315a18bfc7fcc3f0caa7218ddc3b6548eb04be0ded835b5c45ec2ae89
-dist/2024-06-11/rust-std-beta-wasm32-wasip1.tar.gz=97abd2b9a68973263da0116eb5a0b9ead2145c1550f3190d02b35606bb9dcf58
-dist/2024-06-11/rust-std-beta-wasm32-wasip1.tar.xz=4ba0ef9b136761e739ab8ef125ffd993ccf71161d69e7640d94de6d5df601dff
-dist/2024-06-11/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz=886562504ee3e73ceedce6cfcc8d128f22a80f0a33c84b9c29920d7760a8a208
-dist/2024-06-11/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz=a8f28e60aa1938cdc7b7d46a1fa770d587be9534a291f5367a80a52772a0b458
-dist/2024-06-11/rust-std-beta-x86_64-unknown-none.tar.gz=642e7fbeaa76403ccfaf6c3c1bfaa8b94ded7311abfece44c863df231c282406
-dist/2024-06-11/rust-std-beta-x86_64-unknown-none.tar.xz=b1441ef88a1a97ecb6d7b674b571beeefab9f59fc8799d9e63b8a01078042f15
-dist/2024-06-11/rust-std-beta-i686-unknown-linux-gnu.tar.gz=fba54c97da35d0f11af99dca7cb0f43784da2104c461518149974da1f2248301
-dist/2024-06-11/rust-std-beta-i686-unknown-linux-gnu.tar.xz=e7acfab1f7bb8b2c2a0f7558b813f627a3f6b6dadcd05f62c5895f753c2f3ffa
-dist/2024-06-11/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz=e4d5ec39520d069609f32c4dc7dd4114623bcd112a729529a096c992fc19f61e
-dist/2024-06-11/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz=94d508cc6c86516ae5e3bba9366cb466635a1e3f41fd00ba6b1a44a87175fea5
-dist/2024-06-11/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz=76e17967c09311f9e0c684531f21588d5bfbbdd4c707e454068df240fcfa56ab
-dist/2024-06-11/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz=e627a81855b3d93497b071138917dcf6382b60793a4a76073769537531d01789
-dist/2024-06-11/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz=aa5a1b430e31bd5f912d378eab8447ecd920a5840c03b01799a410d86a7c4850
-dist/2024-06-11/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz=20f6fc50caaff58aa2883696c61031e9cec5cc24aea94026cf9b84a7642c4d31
-dist/2024-06-11/rust-std-beta-i686-unknown-linux-musl.tar.gz=62d2daf4c1a0a6b4630559c64bc22ceccd658ea0e9e74ebf58a9b791226964fd
-dist/2024-06-11/rust-std-beta-i686-unknown-linux-musl.tar.xz=34681e4cac9a6e18f1952f51d6192c8b71b970a0edaf0a06766e1a576a7898d9
-dist/2024-06-11/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz=da45a5c9a7c7c1db32d6664358699ceeb27f59247862190a93ac203e5f49f116
-dist/2024-06-11/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz=f881c61a8ed04f02576374a82f28505be2ad4b694254503d30c1ab415b6b5a74
-dist/2024-06-11/rust-std-beta-i586-unknown-linux-musl.tar.gz=2056b8d9d54baeab1fcf7dcf65916645f8404413bff60851fd97108b7822a54b
-dist/2024-06-11/rust-std-beta-i586-unknown-linux-musl.tar.xz=d06fd5dcb976c5331185d308e2ac0e53597275a57603aa171a753b3d005f0667
-dist/2024-06-11/rust-std-beta-armv7-linux-androideabi.tar.gz=27fb1ba34b2331810174f88d0e75075d6af26ef3fb7cd3ec820408e819f36cc8
-dist/2024-06-11/rust-std-beta-armv7-linux-androideabi.tar.xz=f44ff932cecc16cb292a6149ac42fb440b5e4a8a6b56f55634d9031002eb56f7
-dist/2024-06-11/rust-std-beta-aarch64-apple-darwin.tar.gz=3ab3178d3c1d4b9908dc2d0b6236c147e8f787f323c0c02fb924e2d692ec839e
-dist/2024-06-11/rust-std-beta-aarch64-apple-darwin.tar.xz=4b67844f0413cd1b0fde9702542eb2ce297020c29531230c37d3e2f65d56b0e3
-dist/2024-06-11/rust-std-beta-aarch64-apple-ios-sim.tar.gz=317035259b48845882a4561bd1c61108331ce68231b3362fa6e9b0a323ea3fc5
-dist/2024-06-11/rust-std-beta-aarch64-apple-ios-sim.tar.xz=04585ea6b3e53cdf62372dc64f00237d26991a2f7ca6ce06f921065957c2ffc8
-dist/2024-06-11/rust-std-beta-x86_64-unknown-freebsd.tar.gz=048684f3b437110dee704d8ef58f166806d69504a0fbf661ad71d19575cc8436
-dist/2024-06-11/rust-std-beta-x86_64-unknown-freebsd.tar.xz=43762fd9d2cf4dda5e8b64dccbabf5637dde37685530eceba060faeba8212b62
-dist/2024-06-11/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz=40b3feff4834beb31125cffff479288adb2cc8a2d9b8963943907ba2b5478589
-dist/2024-06-11/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz=f088ad7f9697570c251655adbf6921341f74bb8deaa445cdb0d15e5ab556699c
-dist/2024-06-11/rust-std-beta-thumbv6m-none-eabi.tar.gz=94b65456fa327c6d8acd59f1fd004feea8572374e8eadc022338de75c45a6c03
-dist/2024-06-11/rust-std-beta-thumbv6m-none-eabi.tar.xz=9ca368829aaab88a93abb580a0ecc1195ce5fa3877bd556c856ab52af51095ec
-dist/2024-06-11/rust-std-beta-x86_64-unknown-uefi.tar.gz=1a9892b1efce5e6aaa361675e008c623c47056a64deb73246c4211f5194f31a9
-dist/2024-06-11/rust-std-beta-x86_64-unknown-uefi.tar.xz=e9a2df6f754ff4c1ced354250de51939efb1e003843f1d0d8962c2a25e7c0f46
-dist/2024-06-11/cargo-beta-x86_64-unknown-illumos.tar.gz=d6f794f092c47e97e822dd6526ac2622f8a7b3a3cfa8b8462b3378eb16dc4801
-dist/2024-06-11/cargo-beta-x86_64-unknown-illumos.tar.xz=bcf8204f4750c6ea9ff5667ae07de7d06e5b68e78176adb79fc1bc433f7d90c0
-dist/2024-06-11/cargo-beta-x86_64-unknown-linux-gnu.tar.gz=27ba1abe717de9e96b802c8026a17a6b5f5dc728ba4813c705a03d54c234be3f
-dist/2024-06-11/cargo-beta-x86_64-unknown-linux-gnu.tar.xz=55cbb9abf863c05f13049bc59e99ea3e64523f0193ba1dd155b21cb732db50c2
-dist/2024-06-11/cargo-beta-i686-pc-windows-msvc.tar.gz=ceb0b610395fb2519bc6207b7916f402a17fac9685cf8b5c2ee354b350b396ff
-dist/2024-06-11/cargo-beta-i686-pc-windows-msvc.tar.xz=73f1cca9028510331477a0299e214d50a3b9ad02ac035d056acce110f52a1463
-dist/2024-06-11/cargo-beta-s390x-unknown-linux-gnu.tar.gz=eb0dbf227a1ad39436af2334ddb6e90831881c75c24855e9c040bcbb6ce8d876
-dist/2024-06-11/cargo-beta-s390x-unknown-linux-gnu.tar.xz=1b95d58699e8f534b5d93ad02c4281d8e791e8c266f10820de887fe13b1d88c6
-dist/2024-06-11/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz=b078cbb4e2e18b6da3618a1048b038c52bf37a398618179b1c03f25d5e154ce0
-dist/2024-06-11/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz=80bd1e79864e21ed914a6a2b8ee5d66867734252002789c6d76c3f7e82133eab
-dist/2024-06-11/cargo-beta-x86_64-unknown-netbsd.tar.gz=e2fb5140e90588e6ab158352e3f198ea71107a1aa01785f692d5ef64925af58d
-dist/2024-06-11/cargo-beta-x86_64-unknown-netbsd.tar.xz=6bf7fc08f593ef8847b3b14a33783fb3c54c542fe61a8a92c0e462a1bbf34b9c
-dist/2024-06-11/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz=6cc72fe175632e68fefaea683c0569e9fe8f036488154e4f1ccd6a3135479cfa
-dist/2024-06-11/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz=b27004517d35019ead69bcd1a09c81aa20d2b00b57ad42655f1f434f8d66eed3
-dist/2024-06-11/cargo-beta-x86_64-pc-windows-msvc.tar.gz=e5d5945884554970344d16e90f9eed0dd60f61ed57e48b40fac2ee1d7c035475
-dist/2024-06-11/cargo-beta-x86_64-pc-windows-msvc.tar.xz=421ee0fca436d4d4d3bcd03c242f9312fa620da854b906618a1d8ab27979d609
-dist/2024-06-11/cargo-beta-aarch64-unknown-linux-musl.tar.gz=7406ba1c14e53da0a9ca696dc6c90fb816c072734f569c01f49c6b8f7d542d81
-dist/2024-06-11/cargo-beta-aarch64-unknown-linux-musl.tar.xz=917a2e63fcf03be81375143692306afb54fc2addef9f5508dd58fc1729119752
-dist/2024-06-11/cargo-beta-i686-unknown-linux-gnu.tar.gz=bdbd9c4e2808d9dd0acd219c3ba9972634d73fc4f177468bc196c66be620df65
-dist/2024-06-11/cargo-beta-i686-unknown-linux-gnu.tar.xz=e64d3405f99f8ad74984b81238a088b250be4e079e2c05aa68be1cf84f04154c
-dist/2024-06-11/cargo-beta-powerpc-unknown-linux-gnu.tar.gz=bf7c374c02676f9e5a50f4964e6deb4d3aab19ecd66c4d246de0c9a06ebd23bd
-dist/2024-06-11/cargo-beta-powerpc-unknown-linux-gnu.tar.xz=52e7907ca99467c71429d03012a3f6cdd95711b9cf002d3aa06ba25b3e53d2b1
-dist/2024-06-11/cargo-beta-x86_64-unknown-freebsd.tar.gz=bd9aace135befd19104b193e09bf982c79c8cb9cce301ff709cde2ee2dc82821
-dist/2024-06-11/cargo-beta-x86_64-unknown-freebsd.tar.xz=c0d2c3a2e56a1f43f62fb73e41b07def93baa278172d822a2a33f571d54f0463
-dist/2024-06-11/cargo-beta-x86_64-unknown-linux-musl.tar.gz=61526c6e4f0ce1a57d4831ac67252cf5a6cef3c106c6953b329bc0aa9c685e6c
-dist/2024-06-11/cargo-beta-x86_64-unknown-linux-musl.tar.xz=82bcddea6b3d976e7dee07afe7f805f5a6ff66f0721d281d2c896f352f395c89
-dist/2024-06-11/cargo-beta-aarch64-unknown-linux-gnu.tar.gz=70c5bd18c756123f033a7cec027631f71d7400cb4d0c85d7602a8a6309379070
-dist/2024-06-11/cargo-beta-aarch64-unknown-linux-gnu.tar.xz=f8a6c7dd8ba408a5fe623a0ca1d2f8bfe287b13bc09b1d8ea636ebbdec06c557
-dist/2024-06-11/cargo-beta-x86_64-pc-windows-gnu.tar.gz=fe26e842e6e4186437ea679cc75cd37d70a98b1ed0f17ed9ac876aa0501ebd5d
-dist/2024-06-11/cargo-beta-x86_64-pc-windows-gnu.tar.xz=f3fcb2b698736b3df87c06ba829a1f09c218e37b51ff1c59f165aaf8078c619f
-dist/2024-06-11/cargo-beta-i686-pc-windows-gnu.tar.gz=607f623f30e25541d9e6c8412bffcb9c16f7180250a244dfe1e2606edd45db42
-dist/2024-06-11/cargo-beta-i686-pc-windows-gnu.tar.xz=604369c997e05719d0fae92f7904e6b66f662bb75add1d836cb100e0032526a3
-dist/2024-06-11/cargo-beta-aarch64-pc-windows-msvc.tar.gz=de283125b79d17f4cf24bb608819177ac1637525b8c7e67a66e798f0c0b1024a
-dist/2024-06-11/cargo-beta-aarch64-pc-windows-msvc.tar.xz=8228a47ce003faf1edb4a10cf800d3316ba421a97176c97f6952743f7eddf734
-dist/2024-06-11/cargo-beta-aarch64-apple-darwin.tar.gz=8525a4015fa8078921f8bc5f67012c0d5747b7e7111079bffce79f2b696fbd4a
-dist/2024-06-11/cargo-beta-aarch64-apple-darwin.tar.xz=038c700f1b0ab543bb765a4b86638fc7eb1e44257a19d5a5457fcff4fc08f280
-dist/2024-06-11/cargo-beta-loongarch64-unknown-linux-gnu.tar.gz=16c75d17531e10f1bb9e95c79d8c3aa05549db3029663c69d2f56b2d2f3214d8
-dist/2024-06-11/cargo-beta-loongarch64-unknown-linux-gnu.tar.xz=113d97f781bf8d54f457e07fbe3de1d3a0ce0a1f8054a652083b67b81f4cb642
-dist/2024-06-11/cargo-beta-arm-unknown-linux-gnueabi.tar.gz=7856fc9731c3dd7b360eacf422ce358acb2d33a7fd8b16fa190dc77cd9bdb3de
-dist/2024-06-11/cargo-beta-arm-unknown-linux-gnueabi.tar.xz=85c930785fe9857458c9256c5a2849ae223c5dd162bd20ccc8021b2d2ff0a6ba
-dist/2024-06-11/cargo-beta-x86_64-apple-darwin.tar.gz=aa4aec2cf417a7446c2990d03cfb3dcaab9d99f5ac249cbb955a59a64b5b7b0f
-dist/2024-06-11/cargo-beta-x86_64-apple-darwin.tar.xz=01d4bd8dd8a58f16ee31df775d0d7046ce671dc86f8907514e3713a62aadbb12
-dist/2024-06-11/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz=6e5c68d0665add368a6574528184dc1d182e7d72b8da0827b69eb9f9aecbc4ac
-dist/2024-06-11/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz=180a6148f5c5be222d4e2626eed9cd7de2e0f62d0b456e520d1ab7c4931e1f4e
-dist/2024-06-11/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz=6af892aa858f35708bf9db322abf35967b1e92725e05f6974e1d9ee3cb4c7b84
-dist/2024-06-11/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz=40ffc9713504366978bb6f2eea12741400164318945df22290c7b669d3b77878
-dist/2024-06-11/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz=9989b0189f7a4c5aa39c39c78be04e7291cc1358ebed597636f404f56980c199
-dist/2024-06-11/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz=8c7d7dc2530f25cc771c75d454fd11f3e94c7954bb869e43736860be1f253d2b
-dist/2024-06-11/clippy-beta-i686-unknown-linux-gnu.tar.gz=94505902c45770c45a89ea12759bf46cd97efed657b43322d5dd09c13ed26331
-dist/2024-06-11/clippy-beta-i686-unknown-linux-gnu.tar.xz=14830f6fa92b0d814527a9aa5575d0cd529e76dbe2481533b819c735470ad684
-dist/2024-06-11/clippy-beta-x86_64-unknown-netbsd.tar.gz=5cc5f4202003b940a6a62c2384c749b741a9f6d62461ba13a6179464f6c3e6ea
-dist/2024-06-11/clippy-beta-x86_64-unknown-netbsd.tar.xz=01f4f0ef78f17e4991ddf3d974ef7b1dc9d56702ee2d65ede4918e9db99ec222
-dist/2024-06-11/clippy-beta-aarch64-pc-windows-msvc.tar.gz=ee6b64a7a0fc8d8482c38d2a263f9a9ed0b9462e6bd748a72e33c5cd7dac015b
-dist/2024-06-11/clippy-beta-aarch64-pc-windows-msvc.tar.xz=f91457f5dccfc81a601b075da340bf521e3cc17ba05d12f90c31c7f5b215a7bf
-dist/2024-06-11/clippy-beta-aarch64-unknown-linux-gnu.tar.gz=7da546ff13b3e340f2ba22e6995566cb26e487271e3f1b68b3b7dc0bd5122623
-dist/2024-06-11/clippy-beta-aarch64-unknown-linux-gnu.tar.xz=01807b62c65fe33acd05d10191cb16ee1bdeb1bd7b410a9c0cfd8f53006624da
-dist/2024-06-11/clippy-beta-arm-unknown-linux-gnueabihf.tar.gz=64f41430de84569a7b933db7f0c573fecf99f5d0c6900e35598c94a433c0296c
-dist/2024-06-11/clippy-beta-arm-unknown-linux-gnueabihf.tar.xz=b30a73278552ddf511ae82620f14ec7324f281582fa4fa9df3fe984510835aa3
-dist/2024-06-11/clippy-beta-loongarch64-unknown-linux-gnu.tar.gz=e6b0ac4bcec2871d2a50e644733399e684d7fa86798131243c4022cbe2ee5222
-dist/2024-06-11/clippy-beta-loongarch64-unknown-linux-gnu.tar.xz=edc629f04503ce88443ca6cce0b74b5833ce50f428e00a02b544f422577abb1e
-dist/2024-06-11/clippy-beta-s390x-unknown-linux-gnu.tar.gz=ac52f8b4a1b6332aca1ad2363195daf571f7f1870ffa6237441dc7928a408167
-dist/2024-06-11/clippy-beta-s390x-unknown-linux-gnu.tar.xz=96b366fa989d2f739a92ee03bcd141b666b942e0b26922acd620e0fea6d44d8d
-dist/2024-06-11/clippy-beta-aarch64-unknown-linux-musl.tar.gz=8ab584ad05a7836bebb20be8d84b0dd3a29d1823dcee3897abde3a47a10e582b
-dist/2024-06-11/clippy-beta-aarch64-unknown-linux-musl.tar.xz=e7b669a2936a22ed6d2a36b70a6593657488e5ed8d00a911bf33ce51c4c0cc51
-dist/2024-06-11/clippy-beta-x86_64-unknown-illumos.tar.gz=419ef233cfdbe9011d74796e8413a8b6c1f8e6281248969eaf7c9157542c1b70
-dist/2024-06-11/clippy-beta-x86_64-unknown-illumos.tar.xz=673a2f16268fba4d9bf7dca2c0758f3ee60f9754cdcefa36032b8140e6fcddbf
-dist/2024-06-11/clippy-beta-i686-pc-windows-msvc.tar.gz=a3c3bd3b90c951ce404a26a59421f00a03e0dc3351d9dd2876346ff096b7361a
-dist/2024-06-11/clippy-beta-i686-pc-windows-msvc.tar.xz=c3e7c1cc91f48003e1b68fdf753011711ee516bc2ff8c7227d427dd8ee98a72e
-dist/2024-06-11/clippy-beta-aarch64-apple-darwin.tar.gz=ad7b4ac9cfacd860e03f8a41da51b4d279d76b7f3f2f8ac8a048a45f89a7ed04
-dist/2024-06-11/clippy-beta-aarch64-apple-darwin.tar.xz=ca5d2d63b8d7cae00c86383d9075b2292a28d1a85864877a6c8282f5596631f6
-dist/2024-06-11/clippy-beta-powerpc-unknown-linux-gnu.tar.gz=12820c3e8b952dfa931783b550f882dd96c48d3b776fa9cdb29b02d66ad14d96
-dist/2024-06-11/clippy-beta-powerpc-unknown-linux-gnu.tar.xz=394873c6b2499ebc385a11b512c7378b95478a0b6f530c5b313fe86b65a18eaa
-dist/2024-06-11/clippy-beta-powerpc64le-unknown-linux-gnu.tar.gz=8d9353baa4388d02d89b42403e07d6a61f314fc975b8fcd737d8f4edb0ab027e
-dist/2024-06-11/clippy-beta-powerpc64le-unknown-linux-gnu.tar.xz=3cf0511bc5b14619dd6ca1cfeed003effa7fbfecb42fc096a45a211d1ccf419a
-dist/2024-06-11/clippy-beta-x86_64-pc-windows-msvc.tar.gz=cfae39e5d5cbc817aa3ba892822fe2ff122df8a648106aaf0ec18b1ce1a02632
-dist/2024-06-11/clippy-beta-x86_64-pc-windows-msvc.tar.xz=1f1f0596bef154eb3fb4e73993794850f8ad903f4dd0ef9697aa8d5b4d6ec2b7
-dist/2024-06-11/clippy-beta-x86_64-pc-windows-gnu.tar.gz=0909caa93377b2aaf2a05a345e8cfea2c69dc27bd7f7d7a9515576e90cd0aad3
-dist/2024-06-11/clippy-beta-x86_64-pc-windows-gnu.tar.xz=9125bfbaae2103f176b1e1b444fd38c7e74d3414536370037ffc6a85d8567551
-dist/2024-06-11/clippy-beta-arm-unknown-linux-gnueabi.tar.gz=3721470fcc17f8d37c66281bb66c65a66181c80775571520fcc2dfdb583dc640
-dist/2024-06-11/clippy-beta-arm-unknown-linux-gnueabi.tar.xz=79ec48af2925aaad12be405fb72dc9bd9e2ca89fd3a6017111020570ddeb6585
-dist/2024-06-11/clippy-beta-powerpc64-unknown-linux-gnu.tar.gz=d957f503dd4d9d228b6a445eab1183dbc6509a49ccbd475d25143cf1dd28f03d
-dist/2024-06-11/clippy-beta-powerpc64-unknown-linux-gnu.tar.xz=da7ec767b4a85fa327c957888b228671b2311286043165926942504239008d3b
-dist/2024-06-11/clippy-beta-i686-pc-windows-gnu.tar.gz=51ff631084254be43d79d7791000a14ad9f11239e42be73f48383f774109c2cb
-dist/2024-06-11/clippy-beta-i686-pc-windows-gnu.tar.xz=52079acb4f908150d207a838cc7d3c15a725c1d61be35d0d0b2ed85b3386f3fc
-dist/2024-06-11/clippy-beta-x86_64-unknown-linux-musl.tar.gz=99a534de9e5fb552a4e7a10eca2645ad260a723f42e15df3b4e2bacf82e90348
-dist/2024-06-11/clippy-beta-x86_64-unknown-linux-musl.tar.xz=7f9e6da187bb71c384f5040298c43bd303fcbc5e3034dd7fdc7b251c5d7b3a34
-dist/2024-06-11/clippy-beta-riscv64gc-unknown-linux-gnu.tar.gz=acf05b62fc219ddc2fc4e4bca2bc4c2cca24398d6276bd7e7d9f8504627094c4
-dist/2024-06-11/clippy-beta-riscv64gc-unknown-linux-gnu.tar.xz=c737aaf9c4bc3a743752b13159902fc5a8ce746f44221799bbcbcb1f9d04dc4c
-dist/2024-06-11/clippy-beta-x86_64-apple-darwin.tar.gz=422e97d9081e66a46ec3f4c2a7ccbf9b6443c7b343e0a2e90845f233536f545c
-dist/2024-06-11/clippy-beta-x86_64-apple-darwin.tar.xz=c9d02836c9d0e48684f0a343d6935848ec75e1faaf7007a6a3e0718b71e77f7b
-dist/2024-06-11/clippy-beta-x86_64-unknown-freebsd.tar.gz=f207fbfca76eb22f7097eb98ccda1da513fed417371a391e43e8d19fad9b76b4
-dist/2024-06-11/clippy-beta-x86_64-unknown-freebsd.tar.xz=61e39b0aa88a1d8e131a461cb3cebd05154c261058b735f29dc6ed603464b5a1
-dist/2024-06-11/clippy-beta-x86_64-unknown-linux-gnu.tar.gz=c68d27b08f9699c7c2cff9e9bdb7485991d8445074e8b84c2e2222fbff209f83
-dist/2024-06-11/clippy-beta-x86_64-unknown-linux-gnu.tar.xz=d5961f82b9688b9c1ccdcaf578b8325e8ac1e0cc2ffa02131fcc3281cc88dcfd
-dist/2024-06-11/clippy-beta-armv7-unknown-linux-gnueabihf.tar.gz=12ccb5b1d82ad22292b337c49d1c5b0c0d584cfb4e649faf6c53471915df2473
-dist/2024-06-11/clippy-beta-armv7-unknown-linux-gnueabihf.tar.xz=80fa7cb902135006046c10db64d9060103dfb1452e8e0ef256f8344fe0a9c8c5
-dist/2024-06-11/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz=c08499ebec188f67477d0c4eac2e172b59f6d66ad4becb36330b5066af6547d8
-dist/2024-06-11/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz=b3f29c79fc8bd64a2e62101468bbaa28338f444839659d4f99df34ccccad5eee
-dist/2024-06-11/rustfmt-nightly-aarch64-apple-darwin.tar.gz=4866e6d478424fb1c01b2b98678107b9c89e67a2cce3db49833bf34007f868b3
-dist/2024-06-11/rustfmt-nightly-aarch64-apple-darwin.tar.xz=e8e6fd846f70a99e6fad735ce4f4c8bca5f6b5f2d63364c2f8a7df85c13b63f4
-dist/2024-06-11/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz=f14077408a763f0fa6218ed97d7697499c2bded289a5953336c727e2de93bd92
-dist/2024-06-11/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz=27324f62ecfdeeb4a66ce3c62219c491f04ac3822305ea771df0381a5f4e5418
-dist/2024-06-11/rustfmt-nightly-i686-pc-windows-msvc.tar.gz=1147008dfa30891e264bf5f469c9528fe47bdfc729a12215e5a985179513cc66
-dist/2024-06-11/rustfmt-nightly-i686-pc-windows-msvc.tar.xz=95fd945a6c9bcbc9549913906a8f2de20adf54b84b82fe8d981dbb5b767f0cfe
-dist/2024-06-11/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz=4f423c5ce278204dce918ece2af84bdb55429b7a11f630de95a1516e7b113f53
-dist/2024-06-11/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz=c86fe94c9b6cbc56285478ffa715877d234af19f1b58b3fd4b2af23a0267b657
-dist/2024-06-11/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz=f1200f077402474049f6b817688435db0ebef7fb52ef645d5b5d2f7ceea52a08
-dist/2024-06-11/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz=a0d801ec3aa93389d5c6ae2a95be25ba3a50f53182c0a84a00c38a2f708447e4
-dist/2024-06-11/rustfmt-nightly-x86_64-unknown-illumos.tar.gz=d4e28ad9b054cdd19fce6bbc37dc86210b0536aee5c23bca53a6bf1340fdb5bf
-dist/2024-06-11/rustfmt-nightly-x86_64-unknown-illumos.tar.xz=b0958ab975026e09ba921234353f5a81b3227d23c10ded4be4fe37831e6abd12
-dist/2024-06-11/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz=f1caa15f16aa1c93ee783bf273d0ae6a7abd0b38c93c717f2d49af5444cd4e09
-dist/2024-06-11/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz=130687b9de22fb1d0c4c845cff5475e5959278718e3b6a1af7f1b9e8869b527f
-dist/2024-06-11/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz=32e3881c61abfff7f9c006083045ffa5765c0b3a5a6ec46607e5428423ab76da
-dist/2024-06-11/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz=c1859b8a44306b5b3ca27b9226bbf351cd3ff3cacb4faf61200d7baa76009367
-dist/2024-06-11/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz=4f5c23ba3426719c39a7c767be8db83382c84ff7798c5194aefbeda821462269
-dist/2024-06-11/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz=18d9a2084cd5e55792f3841fc7d6602bd4a973726662b516289385b7908ffa4c
-dist/2024-06-11/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz=df5478f63a49c55ffe9cf62a1882feeca019290c0cc9a9ed5a4122b8aa1325cd
-dist/2024-06-11/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz=f54c3b8febfa4023a0334dfeee59d75a44f5c1d3a02d2d57959473d6ad51205a
-dist/2024-06-11/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz=dd2d83a7bcd45a0d5de312a2a4a28b2471a9597d318135214b45a69e1e449f91
-dist/2024-06-11/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz=02a8ada9d737e115033d26b0691f2ef22428ba2f67b7fbab7c4205df8162a96b
-dist/2024-06-11/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz=20bde0cb3ddca790c0d126d5d590b9a35a1c8631b42fbc2d4e85cfe5aa880d04
-dist/2024-06-11/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz=dd29e278f79ce1be14ad44d61039e5a6a63e0e597c4736ab153beb758ad37fb9
-dist/2024-06-11/rustfmt-nightly-i686-pc-windows-gnu.tar.gz=09d98f5c61def16b62b980a6cef3b1b3704cde5c0ad2fdd7d23521db410b6b8d
-dist/2024-06-11/rustfmt-nightly-i686-pc-windows-gnu.tar.xz=ef43e61c2d3d90b09494a8dcbb5d2375223fcba6078f2bfb02ea43750b1a76a3
-dist/2024-06-11/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz=80318fdf7d55c71beb8ff1434b79776c59008f5d62c63530da9f19a67cc18484
-dist/2024-06-11/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz=05ae6d4f8ed07cc75b333e606af14f239978abe197b70409a5f2aadc7de43a4d
-dist/2024-06-11/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz=a079a478e9a89c3a24864b44670bdffcebc139bbec9c54e7aab6394c08bcaab4
-dist/2024-06-11/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz=243c2d7c23e8aeddf9729e1f7f9add6f88f50d012efa02644030110cba111713
-dist/2024-06-11/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz=76b69b4b25e8c0d47b80491bcbb724a25c02d95e7f9cfe7a9c3c3570c24363c1
-dist/2024-06-11/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz=027e075c94f53403f03a4fb29d4575928e1cba141fc0713c93edaa4ea5917e42
-dist/2024-06-11/rustfmt-nightly-x86_64-apple-darwin.tar.gz=b34d3f33e7ae81a5a95927997658d738a3d39db01408dad2d9fa72efb539c73f
-dist/2024-06-11/rustfmt-nightly-x86_64-apple-darwin.tar.xz=7efe129502b732219d1d24d59584b5ad002e7dc5288e047b06bbc81fab36e054
-dist/2024-06-11/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz=231f11ec1c6e4f57556aa32226d22328656d2ceab075cff67c8ab0a1ec32a823
-dist/2024-06-11/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz=b1cd7aa45a516df3a68814ce52753eeead4134943d610449456a30c682079ad0
-dist/2024-06-11/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz=3fb86c9281ae8203e1119bc00e8001afe7e894360adc791a9a0ca1d50e6a9032
-dist/2024-06-11/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz=6380fcfb015a40c4605ff18f8ba54c3be9a8e6a0115ede378565d9cc9943c627
-dist/2024-06-11/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz=f3ff749dedcfb259a4b2d66ae30245caeb79fdec3b41a3bb4f65d50b1cf18120
-dist/2024-06-11/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz=1ca50ca8ff36df7433a4ab4c8a63c3c91e214f6c7889843edfb9120c1f4f68d4
-dist/2024-06-11/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz=a7f5f171dfef5b67498c93354d9dc5a7443d69f3f9bc0bc56b660d1450e9b7a5
-dist/2024-06-11/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz=dff02f7a7e9ae58c41faf4c5731862d11fee06d17099c1ed18863219a4a82815
-dist/2024-06-11/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz=71dc189c1d29d3fec849b47f64deb831569515e56821511b1221983eb9ed99a9
-dist/2024-06-11/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz=17736f80644c8cdf8239940812962e6f55c1924896f79bd2581d20582a9c752a
-dist/2024-06-11/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz=b77e4a1e42c7169d91e268972a9195f7c8494e5cffa5fc71720df799a4eaf74a
-dist/2024-06-11/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz=8cf89f982aaa5559f2cd1721edfdc25f5e99518c418e1a6818c566d668c8f842
-dist/2024-06-11/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz=7703c27800aa2d871624563380596a18deb90081e38cdf6c05cab8e794e5805c
-dist/2024-06-11/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz=ca9dcda51c8945db32e004424eaf26d4f541a51a78be87be0063e5a0b06fdd4f
-dist/2024-06-11/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz=59a2173462baaea0cef3e0f088b4e6ef64e2fe469d1833798d92e844f0126902
-dist/2024-06-11/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz=0cab2fde15bbfab741eead0b084886f8b640aeb181251368464bd833fd08df73
-dist/2024-06-11/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz=8473ef60ff1d5c7aee90b8e0a984c9be7e095446d87e0f13ebcf10f245c0ef0f
-dist/2024-06-11/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz=657a55f27794460bad174c4f9412e771c679c6b608cc3dbe32903efb075418da
-dist/2024-06-11/rustc-nightly-s390x-unknown-linux-gnu.tar.gz=bea7aff88f7d7622a23e91c437d9616a9f1adfbd56ddcb42ee33589d064d5161
-dist/2024-06-11/rustc-nightly-s390x-unknown-linux-gnu.tar.xz=a5ab0850c71e322b1042815c443c79505f1daab2b4a69f8cce05e3761a24f10c
-dist/2024-06-11/rustc-nightly-aarch64-unknown-linux-musl.tar.gz=8c00db9c85fa8053f78285c8a546afb32d6b864795388f1ee7a6a49d12643625
-dist/2024-06-11/rustc-nightly-aarch64-unknown-linux-musl.tar.xz=c137f5f943d1c3f14a4a8b5eca2b541c43c82738452646df524e57a6ef0cbd3c
-dist/2024-06-11/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz=a4087ded3076e4d487efcd4a957554255ea1fad5052a01529ea1847559f7b40f
-dist/2024-06-11/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz=ed2b01ad985668564ba2c3f87dcac4f5c4bcf7ea0b5ecca6a30c1f1c4b63a4ef
-dist/2024-06-11/rustc-nightly-i686-pc-windows-msvc.tar.gz=41db0331bc8f9d164d4198c93234dae41c1b9d2f53d466ee8cdfba4f9704c45b
-dist/2024-06-11/rustc-nightly-i686-pc-windows-msvc.tar.xz=49766cd2ad581f253f3fc0ba4f755a4aeaae954c75d41fa29a9302568e78aa75
-dist/2024-06-11/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz=b57be1a1dc9e70c47564253877bc0cbbdde8a8064a6a4bcf68f8adc6b4c5d4df
-dist/2024-06-11/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz=cf2c4651297993671f033eb9bb9877b157638bc41cb40ccac3294c3fd13786ef
-dist/2024-06-11/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz=619c2eb3ed3f153d2c0ba6cbeb7f0e72c67fbb1e40c025752f94b46c9b740426
-dist/2024-06-11/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz=105560769c3672133ecb063ac0a8ef541229490401470180af75151403287d3a
-dist/2024-06-11/rustc-nightly-i686-unknown-linux-gnu.tar.gz=211498f7eb884908c8110ce922183bbd6cc05d96d9c8b5c9068dcfc4d29010cd
-dist/2024-06-11/rustc-nightly-i686-unknown-linux-gnu.tar.xz=61beb47b917ce644defed991afa6d82028cb8f1e6a191cf5c84e8be883ad3870
-dist/2024-06-11/rustc-nightly-x86_64-pc-windows-msvc.tar.gz=06036f5bfc00950e03a66e8dcab0eb7420fd055aadb85bd42e11845eef122122
-dist/2024-06-11/rustc-nightly-x86_64-pc-windows-msvc.tar.xz=39d3dc95b1e0cfcc381d27540d100b8325728ef9a6a8b72a0e4ad85e2e957a63
-dist/2024-06-11/rustc-nightly-x86_64-unknown-freebsd.tar.gz=9b7badc1c8443571aec7b403e890d14846c3972b02159c8aacf3157ede69af9a
-dist/2024-06-11/rustc-nightly-x86_64-unknown-freebsd.tar.xz=a1fdcbe1ca277b22c2dc8aced8ac0f34f841e7a7512fe421c2b045608c4ce07d
-dist/2024-06-11/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz=5e6105bc6304ea630a8170c785df11cd435521a2ac90348284898c4aab6ed5f2
-dist/2024-06-11/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz=97dc7091b1ffa6a23a4b609a680c1f2f63debab80b5c01bc90fe271d6599bf89
-dist/2024-06-11/rustc-nightly-x86_64-apple-darwin.tar.gz=64769377c3714749acf6404d75f46b00ede0107840e736432d759dbfff15b6f9
-dist/2024-06-11/rustc-nightly-x86_64-apple-darwin.tar.xz=8ce829c39fdf21467307ee540c6b06b510d45c76c395947afdc2e5592d775977
-dist/2024-06-11/rustc-nightly-i686-pc-windows-gnu.tar.gz=4c9425ef2d5fdf9badec75783fe61ce0a251fde672c993c5b0069182449e2d7c
-dist/2024-06-11/rustc-nightly-i686-pc-windows-gnu.tar.xz=442467ab4199e2fb62c69a96cc1c9f03478a415877996f0fef20c54760b2e8b9
-dist/2024-06-11/rustc-nightly-x86_64-unknown-illumos.tar.gz=0b4c3520ff6e5b053a6b37f7d3708fb115fbb99981f337a1786d675e70034acc
-dist/2024-06-11/rustc-nightly-x86_64-unknown-illumos.tar.xz=d192e69dd328e6f930ad5b578065ebab12913762845f68ee55b43ddc9ba074a1
-dist/2024-06-11/rustc-nightly-x86_64-unknown-netbsd.tar.gz=0828f2d9395cdac8e9db6ad5c6b3cab3587fc82bccdec9962cd096e43e4f7793
-dist/2024-06-11/rustc-nightly-x86_64-unknown-netbsd.tar.xz=542f61a4c5a719f2583b0ba820207dc9d09cb9a2bb802da7cfbee5273bbfddfc
-dist/2024-06-11/rustc-nightly-x86_64-pc-windows-gnu.tar.gz=289b1bee22b8d9d84e92461694c6558476f944ac07caf2d22f0c4ccf3d29dbcf
-dist/2024-06-11/rustc-nightly-x86_64-pc-windows-gnu.tar.xz=23c86fc06ed9e7bcf8da72085ff88ec224ccddeca78ddc31032b314cb254ad64
-dist/2024-06-11/rustc-nightly-aarch64-apple-darwin.tar.gz=cf045620e63a5e623047490af956e0daf0bb321ed6a215ae355b8829c047e58e
-dist/2024-06-11/rustc-nightly-aarch64-apple-darwin.tar.xz=0abec976185b9573dbc91868ab4fb84ba2837d25f3fa1d74b3a193609387f3fa
-dist/2024-06-11/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz=0b1146e24e4e59e4577b1e40d3ca45096864e87bcf9f258a34b9d9cf5abc3eef
-dist/2024-06-11/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz=289e97314fd22da08c8943d1240fa94b1cfd2cdf061dea15bfb582a9d482d6a6
-dist/2024-06-11/rustc-nightly-x86_64-unknown-linux-musl.tar.gz=8957493cf92d57381b35d6ce5bbdb408a05c2a6becc8e2cd37b0502e3ef35ffb
-dist/2024-06-11/rustc-nightly-x86_64-unknown-linux-musl.tar.xz=9015e492f773b91054c53aca92ac704336504959779e4b916d42fc966e6058ea
-dist/2024-06-11/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz=aea2dc3831864dc5ea2c389c8208fc82baf1566f4e5688511495db25525e6020
-dist/2024-06-11/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz=9b6f1c3b1656ee2037afe170d6909aa037d484897a83679e2115392a35559062
-dist/2024-06-11/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz=3a962a42e427675df5d8fbc4e638949ec0669a95ecabcdddf5103a9c19f291ac
-dist/2024-06-11/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz=6fe48c92425b41ad7c3e812abe2e5decb117be178a16f6910bd60000fe8f355b
-dist/2024-06-11/rustc-nightly-aarch64-pc-windows-msvc.tar.gz=0a3147dd45cbf54e66b92baec479a5550c63327185baef3df9638c5a740e0921
-dist/2024-06-11/rustc-nightly-aarch64-pc-windows-msvc.tar.xz=d35948d49fa1e526434ca89c2f7542fcfeb86b4ec35bb92f87f387ec37f4ccda
\ No newline at end of file
+dist/2024-07-26/rustc-beta-aarch64-apple-darwin.tar.gz=a265d7831284938f090ef34cf2fb374f4d2b946c52829de8e53a06b7373c3d7e
+dist/2024-07-26/rustc-beta-aarch64-apple-darwin.tar.xz=f2420846f82f474892776f0bea176fbb2f1850a1fb9f51a1afe40ae6de8bbc17
+dist/2024-07-26/rustc-beta-aarch64-pc-windows-msvc.tar.gz=e3e0e2b8d1f8804cc2b5785765cc6807bbf7120fb010d74453097b5931c82e96
+dist/2024-07-26/rustc-beta-aarch64-pc-windows-msvc.tar.xz=1270aaea2f20a378e68d26518e1d34810ed346a4d4c272138c8aef67e3c386d5
+dist/2024-07-26/rustc-beta-aarch64-unknown-linux-gnu.tar.gz=02bcdc3eed81ba17e485556f1c4d5a00e851afb75a20f860ce7b6d22cb8f9e99
+dist/2024-07-26/rustc-beta-aarch64-unknown-linux-gnu.tar.xz=52b72cc7270fe75e023ca9c40d095a84cb0ce31657357cd7676d6570ca59bc1c
+dist/2024-07-26/rustc-beta-aarch64-unknown-linux-musl.tar.gz=b47ba6f2214f238cf8df3c386765e7816bc86e1166f27ddb6c0ce678ec716939
+dist/2024-07-26/rustc-beta-aarch64-unknown-linux-musl.tar.xz=95537778025708922b4bf27f34f0634a61a1d963a8424f8a06c82564c74e849a
+dist/2024-07-26/rustc-beta-arm-unknown-linux-gnueabi.tar.gz=d79c8b744d00b174be7630a54f9ee23562f8977d7e09e2ee46a9d72a80eef514
+dist/2024-07-26/rustc-beta-arm-unknown-linux-gnueabi.tar.xz=0f7d3d0773a3c1f94e8252d95b134f7f5e727a884ece54aa0f77e5edec5c6e29
+dist/2024-07-26/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz=5e0d51532c4bb0c29fd01ef5d931c229f711c9326df0bdcb2b88c75aa72dc210
+dist/2024-07-26/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz=5fe623cab0afd5f7bdd664a593ac02791915e30cfc9ca76a02ffd70e1e865ede
+dist/2024-07-26/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz=1df1e1a44170d6c9ab4988e9841ab56ee00248ca5cbf7e38b69677bd5b2de585
+dist/2024-07-26/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz=70791fcd1aef6686e012740017a0e5bb4441eb4018f875e8e50d5597c183291d
+dist/2024-07-26/rustc-beta-i686-pc-windows-gnu.tar.gz=045fe2478c5a5341d7b7a05b9df23ef8f81ddbe0faa78e3f2107341a0e8189f6
+dist/2024-07-26/rustc-beta-i686-pc-windows-gnu.tar.xz=d7f3888692210b6024ed72864015d1c101f28814dec5b60c9e32a772f11f3b47
+dist/2024-07-26/rustc-beta-i686-pc-windows-msvc.tar.gz=5b2988c87d91013cd92ebca43fd6cf5d49250fc0452830ea46622e418984041e
+dist/2024-07-26/rustc-beta-i686-pc-windows-msvc.tar.xz=b9d65cca6691baf2841432d6d2d566face171c460cf161f39a21acf7c0b033c1
+dist/2024-07-26/rustc-beta-i686-unknown-linux-gnu.tar.gz=7b037163f1c19a0fbbf4029d12a7b3764e747c9ea7944f1e45a6f91a068df224
+dist/2024-07-26/rustc-beta-i686-unknown-linux-gnu.tar.xz=f5044d8f3784e5bc682b03ccbe7389abf5b254a01074fa67eb824d2dfc9fd3ad
+dist/2024-07-26/rustc-beta-loongarch64-unknown-linux-gnu.tar.gz=840131ab570c68c0d46244eac743f7d8a1f470d1926068868d288307a488b3c9
+dist/2024-07-26/rustc-beta-loongarch64-unknown-linux-gnu.tar.xz=6513a144014807bd258d2a90fa4618aabdb4e265268e408d5cb699a610b78c31
+dist/2024-07-26/rustc-beta-loongarch64-unknown-linux-musl.tar.gz=d703a904da3604e553ba0a74775f8005e9f52615be3266197b71362b20414def
+dist/2024-07-26/rustc-beta-loongarch64-unknown-linux-musl.tar.xz=8ab79d34b3c182a4349fd01a50aa13ca064ecea64c2ab09f7a9ec38046741c7a
+dist/2024-07-26/rustc-beta-powerpc-unknown-linux-gnu.tar.gz=70eb8f65e91068ac20366fca1fc30227f36cb2b2ce1abdaa72504583cc7865c7
+dist/2024-07-26/rustc-beta-powerpc-unknown-linux-gnu.tar.xz=3372e272cf9620191000a95fff23e417586e6b894e211d44e4f658c241c3d014
+dist/2024-07-26/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz=e8f09f56c43ae6e99a42a8c430492157415fa6baee2c3f8f86f94ab4279634cd
+dist/2024-07-26/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz=599fcd5c57687e29eec085f7cc2733965a8e8fe5eac6499abd92ffda64f6e500
+dist/2024-07-26/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz=904029f0c81ec9679851d952f0f0f616cc183028882c6686f5b5bb665ca00cef
+dist/2024-07-26/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz=31f3f895d665acf082a6dbb40e91fd97f823f84c8e62074dfa82e60f22606f5b
+dist/2024-07-26/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz=4d374e60b8ac2f3fddd5ba9b46ab80555bc5b19f080b86604dde994087b00ed9
+dist/2024-07-26/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz=c905a880b98d1eaabfb306d5b6dda018e5025b42028cbb12bad408f4d469f3ae
+dist/2024-07-26/rustc-beta-s390x-unknown-linux-gnu.tar.gz=69f0228799685960f36f31eb4c139cbd7925f5180468e2d4a435ecbad63e9535
+dist/2024-07-26/rustc-beta-s390x-unknown-linux-gnu.tar.xz=1da1caf5b2ad149ef82af58278dea6c381c372366c48cda8ca7f520cc8752b2c
+dist/2024-07-26/rustc-beta-x86_64-apple-darwin.tar.gz=81fe4bef33afb3010fdd7af42653fbf5dd9abf0d69268576dfe144c88c7b9944
+dist/2024-07-26/rustc-beta-x86_64-apple-darwin.tar.xz=c4785475e3f7087cbab405937c0ca3ebc08455dd36df156680cea1ed38fcce5b
+dist/2024-07-26/rustc-beta-x86_64-pc-windows-gnu.tar.gz=6e58397829f67bf952037c94894409032e52ac8ccdf3858346d131fff6175a50
+dist/2024-07-26/rustc-beta-x86_64-pc-windows-gnu.tar.xz=8e834602e7cd1fcd585f51ab280266b4ffc57e0c974a1a26b901701b5127135d
+dist/2024-07-26/rustc-beta-x86_64-pc-windows-msvc.tar.gz=94a8a08495b8093db5d9a32c3258c9f97ea8b0f57947d7ca642664c06cfb438d
+dist/2024-07-26/rustc-beta-x86_64-pc-windows-msvc.tar.xz=8d057c7167cffeebeddabf25f08a50de8dbad5ed7cfffce625c81a99d757e998
+dist/2024-07-26/rustc-beta-x86_64-unknown-freebsd.tar.gz=dcc93e7b76ca7a469544597885a7b5f4b5f822e05a89b2d7a093e06dede9f52b
+dist/2024-07-26/rustc-beta-x86_64-unknown-freebsd.tar.xz=3efb7d4d97dc9b13a0178464e79bbf96bb71763a588b48c587746acd456ceb8d
+dist/2024-07-26/rustc-beta-x86_64-unknown-illumos.tar.gz=ef5a0d34b78848962e83ed468934d7cbedff778a89e50f2128ba25d0943e25ed
+dist/2024-07-26/rustc-beta-x86_64-unknown-illumos.tar.xz=5cccc7bbb15b63d422dfd2c8ac25e2103906880e843feccd318ba8b8c614d3b4
+dist/2024-07-26/rustc-beta-x86_64-unknown-linux-gnu.tar.gz=a9b352f61f8124c1fba0c76ecc8c1c972e61e97f5299f3b86bc17f035351ced5
+dist/2024-07-26/rustc-beta-x86_64-unknown-linux-gnu.tar.xz=a8fced9a5de02bb660491b440f6596e4baf6eb9114b8dd8d93ac7ada6266d274
+dist/2024-07-26/rustc-beta-x86_64-unknown-linux-musl.tar.gz=5e6fae2fd75e1780995fa9839593044539fac3f095c8948ba446b7024f632ec9
+dist/2024-07-26/rustc-beta-x86_64-unknown-linux-musl.tar.xz=9eb16965a7f1f7be7751fb61280f272c2497765e552fc0dd653700d551a04539
+dist/2024-07-26/rustc-beta-x86_64-unknown-netbsd.tar.gz=40b7312ce424dcbde5537da50d17854c255c3ed535a124f4f0102cf62bc86b5a
+dist/2024-07-26/rustc-beta-x86_64-unknown-netbsd.tar.xz=222a86f97d9bf2db38ebea9f45901790429658154d3448d05e7f0ddd9833ff18
+dist/2024-07-26/rust-std-beta-aarch64-apple-darwin.tar.gz=a9b3cfe03b3053cd533ff02fb54f95db009396802464f32840b3369e9a3e6afc
+dist/2024-07-26/rust-std-beta-aarch64-apple-darwin.tar.xz=9ddb6b8291ade9224cc76f4d946c179bdc6e25f5819a4ba1ebe1f207d4c663ac
+dist/2024-07-26/rust-std-beta-aarch64-apple-ios.tar.gz=8c129310921ed45d3cdfc30e60d93403adf8158a6661de96ee5d4a63119cf3e5
+dist/2024-07-26/rust-std-beta-aarch64-apple-ios.tar.xz=e1fcee4b062f25b0350e5e74064615c354ee8b399adf792d46319ee782857398
+dist/2024-07-26/rust-std-beta-aarch64-apple-ios-sim.tar.gz=40d6d48dea64407bf31be39f9e0316a1e47648ee75bc0d3361edb961e062aa6b
+dist/2024-07-26/rust-std-beta-aarch64-apple-ios-sim.tar.xz=3e01648f45e0c7cb040d3c293024477801930d5078d54c6291ba13aa8eb4e1f6
+dist/2024-07-26/rust-std-beta-aarch64-linux-android.tar.gz=da310568bee0d4868132589399c9229df5ac575a028f2409f51fd1f8c9e81779
+dist/2024-07-26/rust-std-beta-aarch64-linux-android.tar.xz=f3079ebecbe5b9f23495fe0966fc39fee1d38869287695804c3c04d53df07496
+dist/2024-07-26/rust-std-beta-aarch64-pc-windows-gnullvm.tar.gz=9dce2956e4b01d867ef6c229dbff9319a779a80e43a29fe1f8b10a333049264d
+dist/2024-07-26/rust-std-beta-aarch64-pc-windows-gnullvm.tar.xz=b64e7b87027dceba21283ba71430a8053a918bfaf6c071cc70d5f5da00155944
+dist/2024-07-26/rust-std-beta-aarch64-pc-windows-msvc.tar.gz=0d103e0c4ec8039dd42be09bb9c74f269a9567fe7dfacfc54106912cd2aeb35b
+dist/2024-07-26/rust-std-beta-aarch64-pc-windows-msvc.tar.xz=4b3627e9e363e9b2fd85222c677a7250b12a5d32919f38a31ed7375637a79a81
+dist/2024-07-26/rust-std-beta-aarch64-unknown-fuchsia.tar.gz=061fdac14ee0bd3abba36269f68e9ad25a243ac7062f946155f98680f484a84c
+dist/2024-07-26/rust-std-beta-aarch64-unknown-fuchsia.tar.xz=8acc12f14ac643b822595a6a07c7e5ac65855b83938ac122e3278f64769eeb13
+dist/2024-07-26/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz=199498df7d94989d4ff1773fdfe86e97ac99ead487f402d020f78688bc6dfba4
+dist/2024-07-26/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz=1337c2f00e9bec2e0a553234d74daea67a9781459d0abe3c8de954981d9354d2
+dist/2024-07-26/rust-std-beta-aarch64-unknown-linux-musl.tar.gz=a7116c13a413989f2ed874d45780aced3299c4ef8ce8e3bc99efe960a73cadb3
+dist/2024-07-26/rust-std-beta-aarch64-unknown-linux-musl.tar.xz=80ef87143ee2339e90842c4893284217ddfa56926524baf94341277c1210dd07
+dist/2024-07-26/rust-std-beta-aarch64-unknown-linux-ohos.tar.gz=c47cab4bb196e749f07d03f6f6c8f2fe538c84a055a298f0b505ab98dadf4a1c
+dist/2024-07-26/rust-std-beta-aarch64-unknown-linux-ohos.tar.xz=b36aa3f0bab63ac21fb69610d379a87fbd1ee87041153eb1e6886a237d22b171
+dist/2024-07-26/rust-std-beta-aarch64-unknown-none.tar.gz=92de36c897dbf90f9986396da1f8a954ad7b4fdab3e466d63974c82611e76d47
+dist/2024-07-26/rust-std-beta-aarch64-unknown-none.tar.xz=fb5d50ce34bd222c1b624e5aa2248776f8926f3ee360b7c4c1e0bd412d01bae2
+dist/2024-07-26/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz=fea794a4c8aec3e5357199db7a9b701ceedded1dbb50167b002d368a6ae09cc7
+dist/2024-07-26/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz=47fc6e497bd4c8013f708ed052701129c308b657d28ee2dce877cb63ccb1b06b
+dist/2024-07-26/rust-std-beta-aarch64-unknown-uefi.tar.gz=17eb45b10a0c9cc702e7fb4f0c7926591d3ad0f052f2bded9cf852ea082cd2bb
+dist/2024-07-26/rust-std-beta-aarch64-unknown-uefi.tar.xz=1f6b1a3082fc29546e4d8dcb20675f62ead20fe96112998dcb1260e206e93cbc
+dist/2024-07-26/rust-std-beta-arm-linux-androideabi.tar.gz=baad78bda532ed77dbf3e4265595b9dac82f6fdc27dc6deaf7386a60b981b927
+dist/2024-07-26/rust-std-beta-arm-linux-androideabi.tar.xz=cf4283b1224d4dac3c55da905608c5bba7639b6511977f3de344a999ae39e571
+dist/2024-07-26/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz=0da01efb79d43140515c48561cbe7a2fdb83895fe4351f2fffaaf108fb163268
+dist/2024-07-26/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz=baa52bf16290d71b1b89f12ddcee5adf18c480071f9fd4daf3fcab72f92fad4a
+dist/2024-07-26/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz=2325e8bc225a24a0a8c16da6dded16d4befb671b913051a7cce12ee3e183eac7
+dist/2024-07-26/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz=ab9ad0ec7057deda5c29e5d7de317eb32512fb95b62ba628b91b5246dde9c90d
+dist/2024-07-26/rust-std-beta-arm-unknown-linux-musleabi.tar.gz=be6d9a01609152eb815cef9462023f0ca2f2950ed03d914629d8e6e3a96af8ab
+dist/2024-07-26/rust-std-beta-arm-unknown-linux-musleabi.tar.xz=75ec6023cf9a43ec7ed0f52a1633b56154d9505c5d5d769153b48b9991ce99a8
+dist/2024-07-26/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz=cc1d361b775e966c700d122f925a9f2feacecaf7d2891d9c5c5a4a1060336408
+dist/2024-07-26/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz=934c10c58db5d7644bd0b7df6c3a128cc53b88b412128c33de5932fa0194f4bb
+dist/2024-07-26/rust-std-beta-arm64ec-pc-windows-msvc.tar.gz=949a18d9d8b4c7cb3442ec4e387c91feddf0cc26f1fe602ec6c2c484312c9845
+dist/2024-07-26/rust-std-beta-arm64ec-pc-windows-msvc.tar.xz=7adb9a93d35002d0335b3449b8d9af35a80a35524fe98bd86c3896481f020597
+dist/2024-07-26/rust-std-beta-armebv7r-none-eabi.tar.gz=b40dbc6ba0f3f80414bdc11260f291f067acbceb50d84597a9366746cff53348
+dist/2024-07-26/rust-std-beta-armebv7r-none-eabi.tar.xz=1564c3215b173956bae41cda7312ed7912812e0fbb65dd8d75808a1d5084fc8d
+dist/2024-07-26/rust-std-beta-armebv7r-none-eabihf.tar.gz=809d7f027aecc4a131921181418e66b956ad0a2a7170a3ec3649e21659c5a524
+dist/2024-07-26/rust-std-beta-armebv7r-none-eabihf.tar.xz=1b9589a72d2902cd4491406d93c599d2e850fa2ba19b1bcc6bdc5cc7196f9643
+dist/2024-07-26/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz=f2840d36b089fdbcff5f6f9f7a6e576cf21836824957cdf2d1ef2c75a1f5c11f
+dist/2024-07-26/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz=5723cf48a1ff47fb764cc5ad921356e490997aa09ecd86404e370ffdacfa4b31
+dist/2024-07-26/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz=fb33110ad649aac6f55310e6f03d03d4d75ccdca43ada93fb97a717975ef867f
+dist/2024-07-26/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz=cef39c2886fffef2986e9fe8f3be58f0d7f3846466a35443bc0d49464bdef98a
+dist/2024-07-26/rust-std-beta-armv7-linux-androideabi.tar.gz=68fe7b30550cf1ccc44a1669f26620ae418b48cd6283b716aff3dee91acfcbec
+dist/2024-07-26/rust-std-beta-armv7-linux-androideabi.tar.xz=81f24aedc06a25c8dfce729132a77e90adc5fe2aec86a3a9548aec9458127ce1
+dist/2024-07-26/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz=a63c5d40bcf8b0702c1a91e992c042130916edfdcf94fb4615ba10c89dad6642
+dist/2024-07-26/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz=4706424b53063b768223880d87bbec0cf57e524374a6ef053ebef02d096484e4
+dist/2024-07-26/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz=85c3684f175642463777aa69889a20391e39afc0d6356baa3ac0445f7aa25119
+dist/2024-07-26/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz=a8d67436a8ee232d57e2924f8f9e5cb0050c71740d57a4e677674adb75093f31
+dist/2024-07-26/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz=b3226669f49ee8fc89c1f84855c29f8416df3e32d3276547f521f738179164a6
+dist/2024-07-26/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz=9a5711743a0984ab7baed2a50f87e50d7facff2ef05f5b936b7b25f5a5992734
+dist/2024-07-26/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz=fd2db70418d432c7b32bed92f5af0f301baa3a71c171d0ee8b0798bbc8e239e2
+dist/2024-07-26/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz=97922d70b37e1e2ff6dc447625b3482094824910a1d7a483cc707985406560ee
+dist/2024-07-26/rust-std-beta-armv7-unknown-linux-ohos.tar.gz=710be82238e9ad617b2d5f52ef37976b415e7b6ba3d5f3677080f2ccf78b9d44
+dist/2024-07-26/rust-std-beta-armv7-unknown-linux-ohos.tar.xz=2cd0956277cf963f95ffa0104bdcd60cb4e6c4bb2a443a683d67f41726408159
+dist/2024-07-26/rust-std-beta-armv7a-none-eabi.tar.gz=dd38446053d1500f3bdc325ae5cd52d0434c618d79a7c0a0473c76691353bac4
+dist/2024-07-26/rust-std-beta-armv7a-none-eabi.tar.xz=5b82a2f970be59563cc4f550e4202be802cbe21dcbf14de413ed8f30b0e22020
+dist/2024-07-26/rust-std-beta-armv7r-none-eabi.tar.gz=9758806233e59d7d40eeda0740559d9838f9a6c608309567af61245ea57dc212
+dist/2024-07-26/rust-std-beta-armv7r-none-eabi.tar.xz=4266b69d61a46c0c6f6d3aeb2b3378ff88201039df50cd8d3a51c9ff910be181
+dist/2024-07-26/rust-std-beta-armv7r-none-eabihf.tar.gz=6142ea4cdff99902181379fdb9a651fd9d1ab6276ebc104e73b2280a6d9f380f
+dist/2024-07-26/rust-std-beta-armv7r-none-eabihf.tar.xz=bbf4c74f6b6a32f01d03bf101f69dd19b909717036117064fa2c8cdd0b4146da
+dist/2024-07-26/rust-std-beta-i586-pc-windows-msvc.tar.gz=2cc32752932477945f248dee4d277754928b982815e2e2e0d27883522fb9b8d2
+dist/2024-07-26/rust-std-beta-i586-pc-windows-msvc.tar.xz=e40eae93c31c1fa06517a21cfbdd2dd18e2f740aee1251bcc9bdc680a565241c
+dist/2024-07-26/rust-std-beta-i586-unknown-linux-gnu.tar.gz=6d7210503568d9fa02231ac2d9a1b400d00a37f38ec8f00bfcfe45c325aeed02
+dist/2024-07-26/rust-std-beta-i586-unknown-linux-gnu.tar.xz=cdd81201e38226750f2b4292b099b5d78fe0115cedb4c28bf20200144297d8b6
+dist/2024-07-26/rust-std-beta-i586-unknown-linux-musl.tar.gz=95244114ed2d6dd2de488f49115b11a25b008134f1fa1c8f2e2a62849b51f213
+dist/2024-07-26/rust-std-beta-i586-unknown-linux-musl.tar.xz=fcb3280dabb4aae920a14c7f4fec52dc3f11bc68f5143961fa88347aa020bb9a
+dist/2024-07-26/rust-std-beta-i686-linux-android.tar.gz=d36c3baba2df9d69e197a773f752bc36e107c2411d78037a357039a856e35aa5
+dist/2024-07-26/rust-std-beta-i686-linux-android.tar.xz=14b9bedd1bb95e1bac2bb028670b1d9dbe6998bb6ad0cfab1db0be0cd9e3d4cf
+dist/2024-07-26/rust-std-beta-i686-pc-windows-gnu.tar.gz=44463b4a17c87a2de8554e2629eed8172b60b078ccca7e78bb2b0a20324f51ef
+dist/2024-07-26/rust-std-beta-i686-pc-windows-gnu.tar.xz=1e4c3a1d8585aac5aa3e66541b4aef03a0b429a6067300c58f6cf588eac19fa6
+dist/2024-07-26/rust-std-beta-i686-pc-windows-gnullvm.tar.gz=b1d9d5967c039721eda402a7227074ba6e6e8f2877be49eed961ecbce00004ed
+dist/2024-07-26/rust-std-beta-i686-pc-windows-gnullvm.tar.xz=2436343b99d81abae0e6bba16850dbc1c005ebba5defb991c3a0e99834410746
+dist/2024-07-26/rust-std-beta-i686-pc-windows-msvc.tar.gz=c6147e9c6c39501d133a344972dbb8108bdc45bb2fe8ad624162ad04a9c00c6e
+dist/2024-07-26/rust-std-beta-i686-pc-windows-msvc.tar.xz=6207bdfe0796e4bd4e7d25457d67559f15aa2e8bb91b05284ed147f8799de869
+dist/2024-07-26/rust-std-beta-i686-unknown-freebsd.tar.gz=c675df742bd9fbc01f67411a19926e2814412f12e09b53d1492e8c7250f3e685
+dist/2024-07-26/rust-std-beta-i686-unknown-freebsd.tar.xz=d5b9c3783f6d2dbdf25e0495e32a295c4820bbc5b65a44f19f018b1141e85371
+dist/2024-07-26/rust-std-beta-i686-unknown-linux-gnu.tar.gz=748dfafeb6b953017b9129be9697d02a73d5bc8b1371a6a00bbfa20b7b45033c
+dist/2024-07-26/rust-std-beta-i686-unknown-linux-gnu.tar.xz=0c9a0717054858fa821e4c418b9e99cb0a0f852ec3c866951c1d1795cc1e8152
+dist/2024-07-26/rust-std-beta-i686-unknown-linux-musl.tar.gz=96afb9b33c86a6007f9c02f1f418d28f13014ec5154b648ceb7f725449dcbddf
+dist/2024-07-26/rust-std-beta-i686-unknown-linux-musl.tar.xz=7ed52c039fdd13a7477ed211ad8432cfd2fab98832174c8a534e5ac280f28572
+dist/2024-07-26/rust-std-beta-i686-unknown-uefi.tar.gz=676786bd5e7f0739d18d40d99158045fcba746dc306485c0f15ce49ef2b63b0b
+dist/2024-07-26/rust-std-beta-i686-unknown-uefi.tar.xz=d7fdba095ca515454034891c8a862aaa563ee7451289138ce32b10691dbfe38a
+dist/2024-07-26/rust-std-beta-loongarch64-unknown-linux-gnu.tar.gz=ff2eb11f284da7883dbf6ae465af86e50a9cd98c9b7d22b1e710626716e07db5
+dist/2024-07-26/rust-std-beta-loongarch64-unknown-linux-gnu.tar.xz=953fedb9dac336cb796290f619919f4ff9b2a6fcce09e23072f93a40b5498bdd
+dist/2024-07-26/rust-std-beta-loongarch64-unknown-linux-musl.tar.gz=ba1b4f772faf2e738d2696eb576f74bdbd1fed1a073053eee341ec6423b6e1c6
+dist/2024-07-26/rust-std-beta-loongarch64-unknown-linux-musl.tar.xz=f3f3eaafd9ecb1ee0ba68259d88d65ced56f20323a4f542fc85993e92a044206
+dist/2024-07-26/rust-std-beta-loongarch64-unknown-none.tar.gz=f20ecabfab9d8ecbab44d661018b865e449137993726e76b20c7749db4d0986e
+dist/2024-07-26/rust-std-beta-loongarch64-unknown-none.tar.xz=7da2cf413c0665b07b3083862747c9815a78b3775c2bee6cd1f7551e7f2e4c8a
+dist/2024-07-26/rust-std-beta-loongarch64-unknown-none-softfloat.tar.gz=3f7529ea5dcb17c18efa949916dd1ebc29b123a265cc8839cee4fe4e637f19be
+dist/2024-07-26/rust-std-beta-loongarch64-unknown-none-softfloat.tar.xz=d2a30f8659cc66d48da0e6c1919707943321d7f3ac0e2d58a9078aec16c86ef7
+dist/2024-07-26/rust-std-beta-nvptx64-nvidia-cuda.tar.gz=f971daa3f8c3d0773fb6667cb7a544f96ebd049e9b5d1b5ac4bd3ea0c342467b
+dist/2024-07-26/rust-std-beta-nvptx64-nvidia-cuda.tar.xz=3cd2f4ad7d9f41e9f903aa49eb86d142bb5ef69c2c39d9ba16a00a39d74046f1
+dist/2024-07-26/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz=b319ee87ee034a6a2a67dc2efdc72f8285c73d9bd1bd893586170ac54049151a
+dist/2024-07-26/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz=c751e65bbdfd72de07abf138162ab64dcbce51ba50375cef5ca8f35945d9ac7b
+dist/2024-07-26/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz=0228f8d7e0913cca5db975e0b9ec4807e817dcbc0cd0bd64b64826c9537f25e5
+dist/2024-07-26/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz=d37d5ae3605d745a393fc71c5f0e169cee283aa840edb9543682b339cd040310
+dist/2024-07-26/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz=6dd97a7215bdc8145cee5856957bf3f20719f65c73033006243ac2a9e347394b
+dist/2024-07-26/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz=d7541a8e83f7b8a9761988c3ac295a665e21e4d5dc9e2284ef48314f6c784166
+dist/2024-07-26/rust-std-beta-riscv32i-unknown-none-elf.tar.gz=34b21aec2cc1b92b2911211fe3c798918ea6c99d51975f6a979c2da3a09b0a05
+dist/2024-07-26/rust-std-beta-riscv32i-unknown-none-elf.tar.xz=50ba48e76e60ffbfb2bb0ba0b8e12418b7f6a9d7cde31b508bb4656536934e82
+dist/2024-07-26/rust-std-beta-riscv32im-unknown-none-elf.tar.gz=e84526736c1a48dbec3b122b8c01458ff549afdbdd0f73e705c76cca1bd1f767
+dist/2024-07-26/rust-std-beta-riscv32im-unknown-none-elf.tar.xz=df8d9909b0afd0e02b9c027f12e28aa2c40716d7c8a8f5e82b7521d2e145fbf8
+dist/2024-07-26/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz=7b671c5257a7653481fe6bc090c55398607590292590e0fdf5973f5f9b7b18b1
+dist/2024-07-26/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz=7f4d1a8e757fd29f4f58005032608df709003098eb661fe98a0b3116b7237e6a
+dist/2024-07-26/rust-std-beta-riscv32imafc-unknown-none-elf.tar.gz=9d957edfba201b541bd589ca4085e26bf6f890b3970817fe9af6ccf5f2eb0854
+dist/2024-07-26/rust-std-beta-riscv32imafc-unknown-none-elf.tar.xz=0f867e1391009d1d0caefb6b9217fc8e9f3e087a7dd9b22a157719bdc44ac074
+dist/2024-07-26/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz=a02ccac46574fad8929b419eff7510b8a773211d3ccce9ca96f0485e2dab8eaa
+dist/2024-07-26/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz=b70f37cddd519d0d207e28089b469f702bfe72ba5d32a631c85270db75b83d61
+dist/2024-07-26/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz=151863cece818be834261e6c148eeabbb1c796c991065c84b813bac64e73fef7
+dist/2024-07-26/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz=94cbae695036a4a1fa1faac12a6dd5ebeea18ec2d6e7b01c311d340ce7ddba39
+dist/2024-07-26/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz=3c8ca657208a4d96eff193363375a33d966dc319cd329dd7a0d379e052ab43bc
+dist/2024-07-26/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz=037f7b599421eca888332dadd797509d81af04743eac06120a9882b27aff5ca2
+dist/2024-07-26/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz=d931a3611003cbe61003ca4feeb637449f1d10f7969cd27ca37f11cf5536e465
+dist/2024-07-26/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz=3c7a3a9e1e03c2fe097e2e7353d00d02e864d3964db559f6a08a3d33f1fb7927
+dist/2024-07-26/rust-std-beta-s390x-unknown-linux-gnu.tar.gz=f877200e388345c10d3b0f5b8c484dd42905e769dcc1e21692e1cf7f2d59317e
+dist/2024-07-26/rust-std-beta-s390x-unknown-linux-gnu.tar.xz=1052e8e5681c95ed3c004adee2492ff19d109965e9441a3362df876719899486
+dist/2024-07-26/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz=e487752db0ecd837fb1ecb57064ef2464f7f85ed5fdc9d47322e7b5c37c32300
+dist/2024-07-26/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz=e74a462d598c55822b5841bdc35cb2605b4aa7993e305246b3adf079ae79ea1d
+dist/2024-07-26/rust-std-beta-sparcv9-sun-solaris.tar.gz=3ea692ffe99c953d0049c0a16b71eb0bc3da492b9f9308463311dc0143af84dd
+dist/2024-07-26/rust-std-beta-sparcv9-sun-solaris.tar.xz=97005f0d686a6481c5a532b6e1ea14befc794ed89394a8f1c94ad39257ebdaa8
+dist/2024-07-26/rust-std-beta-thumbv6m-none-eabi.tar.gz=2aa967414bd03764774338e377c4714b8d169b1bbc651624a20158441b8111c3
+dist/2024-07-26/rust-std-beta-thumbv6m-none-eabi.tar.xz=d1a3b6ccbc55d1d9555674d1596a0c9f489304f9cb211e0c4645c17256ada4d1
+dist/2024-07-26/rust-std-beta-thumbv7em-none-eabi.tar.gz=33fe3c61aa2e93c6a925b132fabc11c24e102cc070260d5f89a66e374e9a4d23
+dist/2024-07-26/rust-std-beta-thumbv7em-none-eabi.tar.xz=f50bb682fe484f23ae1ae9b2466c450b8fe9ecc3694fb68e162ce43cc8917af7
+dist/2024-07-26/rust-std-beta-thumbv7em-none-eabihf.tar.gz=53a17d10d498f1b6ebd6852987f304b2e1187544f2c9e91b69d0fdbf88630910
+dist/2024-07-26/rust-std-beta-thumbv7em-none-eabihf.tar.xz=fb97e6f2b047d6251eb6e34891b64f20d0dbc648beb78bb7364fe563670d7de8
+dist/2024-07-26/rust-std-beta-thumbv7m-none-eabi.tar.gz=940eef037faceb2b9bdb1094eac6b175843094d3a3ab3c9850eb28742643e92d
+dist/2024-07-26/rust-std-beta-thumbv7m-none-eabi.tar.xz=c892b8a80db788d1f4bf64ec6f740bb1168a8b9dc88d105366892a476ad3c244
+dist/2024-07-26/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz=905d378e6fd4387381fc166718ff31f017c99e725a9c8461bbac39d5571e246f
+dist/2024-07-26/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz=6c5fc29004bda36ddfb0280636ac2b2c28c538f33cadb07a55174fadb068daa5
+dist/2024-07-26/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz=38c8b07558734a9fff1807a823af72faaf8ab5ea47042f1b88a38d6c3648c43b
+dist/2024-07-26/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz=e30e0000336449a8aabf60839cba4ecca32cf82b02ed0a7a23935793072679f4
+dist/2024-07-26/rust-std-beta-thumbv8m.base-none-eabi.tar.gz=db784556ebf56a79e6330de3204ce6ce5422eca2543b872ed55c238aedbfedae
+dist/2024-07-26/rust-std-beta-thumbv8m.base-none-eabi.tar.xz=373efe8c55e85aae60dfac234471b76fefbc2ba722d97e0338ec593b7c70cce3
+dist/2024-07-26/rust-std-beta-thumbv8m.main-none-eabi.tar.gz=1bd5a11163f5fb9325e21c425d5d2fb3e1f845d265cbf7736679c3bb9c8d22a7
+dist/2024-07-26/rust-std-beta-thumbv8m.main-none-eabi.tar.xz=d858d0077df0fa7363258994e76a1bc0ff850734de6a0fbe955c3c9b9cd46cb7
+dist/2024-07-26/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz=07b356cd0ec3f18617e8f5be04d784847acfca43d6fa2101821dcdee18aada36
+dist/2024-07-26/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz=aecacd11945e6e053fe27faab2c0816628b392cb06c41feb8ed693d43043eba4
+dist/2024-07-26/rust-std-beta-wasm32-unknown-emscripten.tar.gz=7bf6bdb443503d48cb711f8b3e2670fe20e02f71ae940c2f1b273ab1d15452b7
+dist/2024-07-26/rust-std-beta-wasm32-unknown-emscripten.tar.xz=9ed34d7467722660d625e9a048fcb843bdb80aac407b0395a693a5698f6c1465
+dist/2024-07-26/rust-std-beta-wasm32-unknown-unknown.tar.gz=5144fe563c42205ba777678291950bd1b8c2b010b9aae28e2fe96e14e93e28cb
+dist/2024-07-26/rust-std-beta-wasm32-unknown-unknown.tar.xz=6e55e79f65a02abf37e1533c2590f53dfe56b474b58a3220d88f3d1458b6dcdc
+dist/2024-07-26/rust-std-beta-wasm32-wasi.tar.gz=84d03b1c1fc7338895f82f54fdccb18ea6c4ceb43f47c3d46fadb014aa0c9549
+dist/2024-07-26/rust-std-beta-wasm32-wasi.tar.xz=f28cbf9552e3c680342364087e7305a12417a92ed6b6696d71d476e1c1d8d4e7
+dist/2024-07-26/rust-std-beta-wasm32-wasip1.tar.gz=8d56f1aa8661047f854806278b83a514fa79b7a5097635cd095943b3f848ea74
+dist/2024-07-26/rust-std-beta-wasm32-wasip1.tar.xz=78609204d01e0d0bcbc1fb5dd3d9cfcac60db23bfbd2428f1e021d1b05793519
+dist/2024-07-26/rust-std-beta-wasm32-wasip1-threads.tar.gz=ed1b9141bd68b8c13e295904ac66d18ca92c5b92a263fa5109262d15065aeded
+dist/2024-07-26/rust-std-beta-wasm32-wasip1-threads.tar.xz=0c036271c4c4e04357b630146cad296dc6a57363f7dc0cd2f3142ead13bf0602
+dist/2024-07-26/rust-std-beta-x86_64-apple-darwin.tar.gz=c12bc5543c262645f7000cc84247518033f15fcbdfed510eb92393d723906eb1
+dist/2024-07-26/rust-std-beta-x86_64-apple-darwin.tar.xz=a5fc26dd6068cdb28ee2a252af545a34dd2be6e075e7d0aac2d03796c07579f4
+dist/2024-07-26/rust-std-beta-x86_64-apple-ios.tar.gz=a62be7f900cec101b1b7444c7466e8fe0b823d708fadd92bce8bd531866b4938
+dist/2024-07-26/rust-std-beta-x86_64-apple-ios.tar.xz=993875efe27c1018bbcb8326665247a33eda6fc0e934f71124b0a08d72685474
+dist/2024-07-26/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz=bc6ae4d5e93b47828678f1af55efc1baae2d76975be3259854272a566f5489c9
+dist/2024-07-26/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz=51cf1d675e61aaeedf895e52a9a81b188aa066a68d599963e0435bddfd2f6a5b
+dist/2024-07-26/rust-std-beta-x86_64-linux-android.tar.gz=6bd4089f30f05d9902d667a2d48028345bd558e7365bd3957bc554a4d0c1f939
+dist/2024-07-26/rust-std-beta-x86_64-linux-android.tar.xz=2a7e9250e3bea7f7e502131012139eadb66c71e95e8cec1698e22b21e7c9fbcd
+dist/2024-07-26/rust-std-beta-x86_64-pc-solaris.tar.gz=4169c938b638faff18a5db1bed5e7d2036f45d25ec9799dc2967ad1589d447a9
+dist/2024-07-26/rust-std-beta-x86_64-pc-solaris.tar.xz=8cbda8eeb98be575b78170e9895390e9406c4de41db8363988185dd24e276427
+dist/2024-07-26/rust-std-beta-x86_64-pc-windows-gnu.tar.gz=99a14bf8cffa0c736a25ce117bc5d4ab64963d81c9d9ac377f118a77a6a3c4b6
+dist/2024-07-26/rust-std-beta-x86_64-pc-windows-gnu.tar.xz=9902878b75b3f6cf944909cf6d17efc26dc820708b164b34757d841e89c948bd
+dist/2024-07-26/rust-std-beta-x86_64-pc-windows-gnullvm.tar.gz=54b83918128c3d19b09a4e1801783500266794395e6a6f138ad647bd890b79f6
+dist/2024-07-26/rust-std-beta-x86_64-pc-windows-gnullvm.tar.xz=2b0ed80c922e25f3783fbc0ce181b76b7f758d2a1b85b823851b7ac35c6872df
+dist/2024-07-26/rust-std-beta-x86_64-pc-windows-msvc.tar.gz=44ce7faad791029b670a9d815766a647d488dbbb56eb09024a09a595427fd19b
+dist/2024-07-26/rust-std-beta-x86_64-pc-windows-msvc.tar.xz=cd7011512df191100d31caef920d1a5c6d5ec2a771e0b52078d5d60b45e9a497
+dist/2024-07-26/rust-std-beta-x86_64-unknown-freebsd.tar.gz=dc20c2fc14b2211bf4517464109871f940a227298302d2ec84eaca539a19e9b4
+dist/2024-07-26/rust-std-beta-x86_64-unknown-freebsd.tar.xz=5a7fa24ca3f7b43526c116a5ebce60f29116640ad51c1ed426f9aee705b10897
+dist/2024-07-26/rust-std-beta-x86_64-unknown-fuchsia.tar.gz=975917e862347f7e1472cdaa2258de16cb9981e3a8256f9b7860104740076187
+dist/2024-07-26/rust-std-beta-x86_64-unknown-fuchsia.tar.xz=bb89062b05f025a964e0110fcfc8fdf57300b23314409924cd4a05e9af9614af
+dist/2024-07-26/rust-std-beta-x86_64-unknown-illumos.tar.gz=a1c1e3e15bea1c4e6c70b8a56c4fef1c231b6ab5528c32cb69ded38456b3fa21
+dist/2024-07-26/rust-std-beta-x86_64-unknown-illumos.tar.xz=43b31f7dd50621faff96c13a2246c80e84fc4da4076d4aedca4e9a6bf63ca43b
+dist/2024-07-26/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz=3f8df0e35e2e8d5e0f8181f20f0639323aa8e8c21da60697599447c0d77f783a
+dist/2024-07-26/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz=d0e727d9176abdbef02b1276b3b1acf69068b9c0fc0477fb3248fd06c99292b5
+dist/2024-07-26/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz=73ba835c5c4c9fcabbcb4e1460d402cf0c0aa9b2e01342521897abd9769dcc02
+dist/2024-07-26/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz=64e6fc64ccfd0adb2fabc610eba6e877ab83f2de49532363deef4579728baf6f
+dist/2024-07-26/rust-std-beta-x86_64-unknown-linux-musl.tar.gz=58dcb73ba02fa38742d255bd346a77340cf634247904624c7af9b11e769a364c
+dist/2024-07-26/rust-std-beta-x86_64-unknown-linux-musl.tar.xz=ea4417de121ab7e869659b26efd144baf2fd839a956da4acb30121d1bc9132aa
+dist/2024-07-26/rust-std-beta-x86_64-unknown-linux-ohos.tar.gz=d1e861a9176a5cb934270592f7b98528283c363d135736477a844499015ac44a
+dist/2024-07-26/rust-std-beta-x86_64-unknown-linux-ohos.tar.xz=c5f548845c6ccbee1980892e630ab06ec1bef498fb7f6fc80b4ced4a84c23f85
+dist/2024-07-26/rust-std-beta-x86_64-unknown-netbsd.tar.gz=3f6677ecdb1a2f016e9941234c221b06fd0a21cd9bae83a59bdcfde055c4878a
+dist/2024-07-26/rust-std-beta-x86_64-unknown-netbsd.tar.xz=60eae08756d92a70b740ecd8a1412138a9a14486289d73440bf7ee068586f9c4
+dist/2024-07-26/rust-std-beta-x86_64-unknown-none.tar.gz=1f11ad1a66d01a09c7237da76327b70ae2e2a9f7647a3ee0de58d563576efacf
+dist/2024-07-26/rust-std-beta-x86_64-unknown-none.tar.xz=960fb614a927e1b3d1d8e4a9fb7220ae675d0e8219fdde204bc6454fbe69a0a9
+dist/2024-07-26/rust-std-beta-x86_64-unknown-redox.tar.gz=3af955fc52feaee2d89d6d50e0df4d00417897679f0d607a0f146a8d34c20496
+dist/2024-07-26/rust-std-beta-x86_64-unknown-redox.tar.xz=cb607387d0524bc84610cd6cc0a0070e0dadc379a7fb1a736f3f336cf0458b8d
+dist/2024-07-26/rust-std-beta-x86_64-unknown-uefi.tar.gz=ae56b334234ba51cf68be42d0fd58cf3487673dbe747bb3efa01e8563b9b8a90
+dist/2024-07-26/rust-std-beta-x86_64-unknown-uefi.tar.xz=1468622e9bb6384a6ab7006863d2b7d55307e74239befc8e72dfd39f83c0af1e
+dist/2024-07-26/cargo-beta-aarch64-apple-darwin.tar.gz=62f687da4c02bef3e114b92c75b62fc6f7fdfcd210fb66329f6d4780f7dbcd70
+dist/2024-07-26/cargo-beta-aarch64-apple-darwin.tar.xz=f9346e9ed4e5638f58dc237b22aef9e1b25b23bb588c736dceaa25b7b935f2bb
+dist/2024-07-26/cargo-beta-aarch64-pc-windows-msvc.tar.gz=f2442eab2908bb90c551f56da8889e39ce44a31936ce63e13a54432105a67cf9
+dist/2024-07-26/cargo-beta-aarch64-pc-windows-msvc.tar.xz=ffc8c803668d09333fdfee996fa72c8874e91d92567f0b4eff9077d7b9a3070a
+dist/2024-07-26/cargo-beta-aarch64-unknown-linux-gnu.tar.gz=97f6b771f7e559df03f00f8665c6580535499d4afa7bf2a252a145b1aa0e2c0b
+dist/2024-07-26/cargo-beta-aarch64-unknown-linux-gnu.tar.xz=3ee58d5c57ba00e27428392dab1d69655bf7e997a0d3aa6629bb32f4f863396b
+dist/2024-07-26/cargo-beta-aarch64-unknown-linux-musl.tar.gz=b36871d3c88eca54e4c24d50171fd649d10a92f689d4812ebef7b510f0c3d799
+dist/2024-07-26/cargo-beta-aarch64-unknown-linux-musl.tar.xz=ee550d60ae217fe7aec12feada1ba1f84222427677de42382d192ec748f73f18
+dist/2024-07-26/cargo-beta-arm-unknown-linux-gnueabi.tar.gz=6599270c877164e76ef30f00a9b47da1a021fdaf1d4f7fdb194500f861ca8d21
+dist/2024-07-26/cargo-beta-arm-unknown-linux-gnueabi.tar.xz=46429528039b5499c6ac4618c4b73fcdfabf7fdd5ed9f9f3d64ccde0428d78c0
+dist/2024-07-26/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz=01ba37e80e18e673c275538fc0db63b667ef52a72000dcbe76ac68018bd585e8
+dist/2024-07-26/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz=004f5119454fa53c2a7a58f6d176f65903b3c5bfc8eb1f894f6ca4e9bc32b7a1
+dist/2024-07-26/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz=2bb2e69563684bf64607d3f584b4216b24fe190dd2eabd6c00c2044290beabde
+dist/2024-07-26/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz=454b0dafb3cd62788dc541ddfea5b484ac799253937602f6456e853c2a293707
+dist/2024-07-26/cargo-beta-i686-pc-windows-gnu.tar.gz=779d704f8f64a7290227631d1e396fe00bdada3cfb7f3e6c775a0bb00047cb97
+dist/2024-07-26/cargo-beta-i686-pc-windows-gnu.tar.xz=8cce8e286ff04f4d58235e8716a0ca05aedfeb9db6fb8952c523264ea649e542
+dist/2024-07-26/cargo-beta-i686-pc-windows-msvc.tar.gz=58b31a781da4f5215b0fbb5f355cbc3c5b2212971c68a1e00de19b851698fda3
+dist/2024-07-26/cargo-beta-i686-pc-windows-msvc.tar.xz=008125eca7351844707c9c14637030da45441a68d74f6e2752ee713f6403f03b
+dist/2024-07-26/cargo-beta-i686-unknown-linux-gnu.tar.gz=cbfc580db37b135a20f42f9da02517ec8cf0a286b7274252c23c6a4947ba6755
+dist/2024-07-26/cargo-beta-i686-unknown-linux-gnu.tar.xz=dc2198fabb6fe6f68353c268698dece4ca3d6901b424a7cc2c68850f81f75f20
+dist/2024-07-26/cargo-beta-loongarch64-unknown-linux-gnu.tar.gz=46ea726328e1700cf2b7d0ddeb16e25ebb648267c76268ba2f4aecb75ba47661
+dist/2024-07-26/cargo-beta-loongarch64-unknown-linux-gnu.tar.xz=520ee25c1f18d80b4e4ce25e8fd961a19c0dd2ee0274e9d9cd3201f7c57c6f77
+dist/2024-07-26/cargo-beta-loongarch64-unknown-linux-musl.tar.gz=fb710b6ae058619042bdf80ef5c2a56457076692a122b4155e0a53f382e8ad83
+dist/2024-07-26/cargo-beta-loongarch64-unknown-linux-musl.tar.xz=ac15e80c28c7a4570bb4a99fa70522a3ae5ba602ce25e96b8e82d097f8b42904
+dist/2024-07-26/cargo-beta-powerpc-unknown-linux-gnu.tar.gz=6907a40c1e7b18146ff2a60c6d44c9716f31cd4aeaae4fe858032aa26c359d27
+dist/2024-07-26/cargo-beta-powerpc-unknown-linux-gnu.tar.xz=4287d73ae2b3272a1893c2ffa32d007edf0b05ff2dbf1da92aa20f2b857e0eab
+dist/2024-07-26/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz=edbdd5fc1e9bc5fdea67e7c2fda3fa9f3eb3f599c307a278bc7bf45ff97d1f48
+dist/2024-07-26/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz=9c7d487f65a6273b76970b2c057b8120abbd89ba67a2f92dd446ecbacf218576
+dist/2024-07-26/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz=74e57cbc139d548202d94262170ee45e33ae01331358ac2eaa9fa67c968ea1ea
+dist/2024-07-26/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz=6cf99b689e32ff0caa56e9704dd185f6c268b484ccb657eff212e66fe64d1c10
+dist/2024-07-26/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz=ed13a39d74e9d814d585ce7fb1aafd093f94317d6ead76e4b43c03b01e210086
+dist/2024-07-26/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz=b5379d677d6596ffcbd7f3ebef2fd6d968096228101104a45565b170fb050042
+dist/2024-07-26/cargo-beta-s390x-unknown-linux-gnu.tar.gz=1a29502881e6512a8bea566a90781870181f5727359668fa3bed2b3210a21b8d
+dist/2024-07-26/cargo-beta-s390x-unknown-linux-gnu.tar.xz=95970245a7f304c6b83b8dad58b4c877ad2c9b0ca6bfc0090151561ce53a217b
+dist/2024-07-26/cargo-beta-x86_64-apple-darwin.tar.gz=521f03a968c6e0640de6f09ecbc6328ea57b2815f353a14e1d4dd09925e98366
+dist/2024-07-26/cargo-beta-x86_64-apple-darwin.tar.xz=14b733585cc768d26a822de630d990f519b6d6b4ae079f09bacd51b7449c18a4
+dist/2024-07-26/cargo-beta-x86_64-pc-windows-gnu.tar.gz=1bf5d0201ca87a76de8044dd8222517bd130ef3db631dc60a84e2fceced465d7
+dist/2024-07-26/cargo-beta-x86_64-pc-windows-gnu.tar.xz=2eaeb6863c655047e6c938e208ae952df4da2d8b4326aeda60918414764aa7b6
+dist/2024-07-26/cargo-beta-x86_64-pc-windows-msvc.tar.gz=7b7ef80aa6131ddcb8bfec0f9493417e9a1e617a8f599a27de52ee914d022f95
+dist/2024-07-26/cargo-beta-x86_64-pc-windows-msvc.tar.xz=647a6d0ff8f38dd4404c0006e5ed7b3a981dc89bbc334b1bd53225cc4f5511c8
+dist/2024-07-26/cargo-beta-x86_64-unknown-freebsd.tar.gz=bcd0e100d4c66784a2357be74813551c68d4e3b5e6846bfd1bbcb316e5c82c53
+dist/2024-07-26/cargo-beta-x86_64-unknown-freebsd.tar.xz=cc31bb9f5a67359f4af4743afbdf9b694e40cd209211d4ea819c94183de6ab60
+dist/2024-07-26/cargo-beta-x86_64-unknown-illumos.tar.gz=12f6a8d3d17b54ea260f6f5b19be9e208111b0ad37518ae6b6eae558d77a1dc5
+dist/2024-07-26/cargo-beta-x86_64-unknown-illumos.tar.xz=221c9cf9d1fce2b5c50bcf8f435f5335f1c5e9533f51d52b941593d6a964b4c8
+dist/2024-07-26/cargo-beta-x86_64-unknown-linux-gnu.tar.gz=53c64845abe4582a90041b2128b3f931ce636d01fc9a8509b35ded5dd7ae0a35
+dist/2024-07-26/cargo-beta-x86_64-unknown-linux-gnu.tar.xz=61805cfca6e7f602eaab0fde2be48cfed244105b2f4b5bff798752ce06d62713
+dist/2024-07-26/cargo-beta-x86_64-unknown-linux-musl.tar.gz=92ac04de9689176a42e5f0ccf1e44ce78b64bcd15d6e570c171d51c44cf8c6ce
+dist/2024-07-26/cargo-beta-x86_64-unknown-linux-musl.tar.xz=59a371de4343d330b79e84f629c98b5cb9dc58bd9706d1a7a9ff474b28394851
+dist/2024-07-26/cargo-beta-x86_64-unknown-netbsd.tar.gz=f48bb7b7d13862edaa8949be046b5bd2b8c63b0aab8e29bffb1940ec149eb123
+dist/2024-07-26/cargo-beta-x86_64-unknown-netbsd.tar.xz=0a6e09604fe291d0a9a0845a8ac7f434c9f4ffbb698c042ba83a070c23f804fb
+dist/2024-07-26/clippy-beta-aarch64-apple-darwin.tar.gz=4c8991c692f200c6a5f25957e6648e07b7271681cbd9c61749bc990216dbbe6f
+dist/2024-07-26/clippy-beta-aarch64-apple-darwin.tar.xz=51b5b85d46af2a3faeb53b81472c285eccc01f0c83575f62f37739cd48397fe2
+dist/2024-07-26/clippy-beta-aarch64-pc-windows-msvc.tar.gz=3a7755c10b32ee3b4f95875c974f21efad2be7ae27d317bbac056b3e5b9298b7
+dist/2024-07-26/clippy-beta-aarch64-pc-windows-msvc.tar.xz=718692e6a1e00ca042d9767273e487c941c65440e64729844a46e42ec6a8abb2
+dist/2024-07-26/clippy-beta-aarch64-unknown-linux-gnu.tar.gz=18da4a1fac25597186bdc5c825c71bc6fe020e8e6552ac97dd307a0311acab20
+dist/2024-07-26/clippy-beta-aarch64-unknown-linux-gnu.tar.xz=86a7ec123586e0c953efd23b82aea5eab62ab8c065bf3596d3001a23b01243ce
+dist/2024-07-26/clippy-beta-aarch64-unknown-linux-musl.tar.gz=267b8dd0b5024152e36bcfb15af0b8ae3c68a71f559b8ecea1a3c9a8982e315b
+dist/2024-07-26/clippy-beta-aarch64-unknown-linux-musl.tar.xz=6aaae715599da14ca8cc405e51deed3bc160661ec56e929ae347ef1ead7ccf00
+dist/2024-07-26/clippy-beta-arm-unknown-linux-gnueabi.tar.gz=f794412df97e19240f628037f5d1d7391dd09ee1a6de02f4dbff72e2b03d94b6
+dist/2024-07-26/clippy-beta-arm-unknown-linux-gnueabi.tar.xz=49a78a14b9638cabd19ba4261f5bd04066646e1260146e3be288182b73fa1864
+dist/2024-07-26/clippy-beta-arm-unknown-linux-gnueabihf.tar.gz=3dcd9775b46a100a50fbb00188dffdc6f07fca9843994c8406a2d053e41c1672
+dist/2024-07-26/clippy-beta-arm-unknown-linux-gnueabihf.tar.xz=e069b852ace430b2f75486a291d3d7849439c67c3381f5eedc0d6a9e6cde56db
+dist/2024-07-26/clippy-beta-armv7-unknown-linux-gnueabihf.tar.gz=57f7109bef934d0da06f7aea6eaca72b0e66f82d1160fbae05f53c2276da2b82
+dist/2024-07-26/clippy-beta-armv7-unknown-linux-gnueabihf.tar.xz=5ed50d8d088ae0d86ba51a03bf56040da027376f70b5114f593813daa4ce7a40
+dist/2024-07-26/clippy-beta-i686-pc-windows-gnu.tar.gz=d8712ca2ab26256c0fade4ecc8dd8e4ea6770d91e16e460ff2fe3f070febc59f
+dist/2024-07-26/clippy-beta-i686-pc-windows-gnu.tar.xz=9d0c88881e0535f9cb4a48f59b389b1c2a0b5fa46ad8bfa37fbc540676a8f557
+dist/2024-07-26/clippy-beta-i686-pc-windows-msvc.tar.gz=ffa017562648e98c7229e43a7422602c265441228485f0e14e52ebaf48a13e91
+dist/2024-07-26/clippy-beta-i686-pc-windows-msvc.tar.xz=292ab3d318a34e67463728752dc175f65cf5530f9368344dccaa79bad4df3b85
+dist/2024-07-26/clippy-beta-i686-unknown-linux-gnu.tar.gz=89bd927bc9370a405561f6534c5cd88e0f6e06b0b512589e5722349b12a17763
+dist/2024-07-26/clippy-beta-i686-unknown-linux-gnu.tar.xz=732120c4fcdde08fadca139216a91af7a6abee15f0a41735dc8860b36039d88d
+dist/2024-07-26/clippy-beta-loongarch64-unknown-linux-gnu.tar.gz=101e3118bf23246195b159abab59ee5626e767977d97f00e71fc5e67dfbf7784
+dist/2024-07-26/clippy-beta-loongarch64-unknown-linux-gnu.tar.xz=e40c0c15a7b195ed03c5e1167c2cb5e765ef643b0f6621c36643faf87bf46369
+dist/2024-07-26/clippy-beta-loongarch64-unknown-linux-musl.tar.gz=f6ed6391c8997f942d180cd32e81aca654450fb050cd865a8a1b13f77a892245
+dist/2024-07-26/clippy-beta-loongarch64-unknown-linux-musl.tar.xz=16e736f65b0ff029fe9fbafceec938123dff1b5a133f6c48b25edab379a20685
+dist/2024-07-26/clippy-beta-powerpc-unknown-linux-gnu.tar.gz=711fdb406a23ab5c3b1199e7af06608297bd071d7e48734a03bbc1f7a00b66dd
+dist/2024-07-26/clippy-beta-powerpc-unknown-linux-gnu.tar.xz=36d05ba29927b56e0d815dd09b39a3db12b6395e9717e653c20449fa83aa636f
+dist/2024-07-26/clippy-beta-powerpc64-unknown-linux-gnu.tar.gz=d53fb59c723a2e76f1716cf1c82aacd2627e1694aebf70511c24529a4fe1ee99
+dist/2024-07-26/clippy-beta-powerpc64-unknown-linux-gnu.tar.xz=ffec66667d95cabc893cc87988218552eba8930f031419612f80144dcf2cc881
+dist/2024-07-26/clippy-beta-powerpc64le-unknown-linux-gnu.tar.gz=a2cd11651304ecf5ce6a1ee5fdd1acbfd36b1dbd2680cd76f2b9d3a86012b837
+dist/2024-07-26/clippy-beta-powerpc64le-unknown-linux-gnu.tar.xz=c8a8d9fe8badb1e06811412a15ce9cdfef07ecc59bf83cd578b33889751bb560
+dist/2024-07-26/clippy-beta-riscv64gc-unknown-linux-gnu.tar.gz=01ba50dae501edf3afa60aab59d8d81ccfd91126ded4cf7d45f7c4b13fb8c4aa
+dist/2024-07-26/clippy-beta-riscv64gc-unknown-linux-gnu.tar.xz=a7e749bc581f9c64137a00dd891c4abff0d7f5684d2d501aad20ed1b01d9a312
+dist/2024-07-26/clippy-beta-s390x-unknown-linux-gnu.tar.gz=f19081755c37e3dc43091b06bcdc59c82b28c6fa0a78ff02d800a25d6d9f22f2
+dist/2024-07-26/clippy-beta-s390x-unknown-linux-gnu.tar.xz=d5f222e23f4f0ed4929e11684bc7b861c29fa183fffba0dbbfd5739b921f5234
+dist/2024-07-26/clippy-beta-x86_64-apple-darwin.tar.gz=edd631b7938dae6bb6c2694df0dab3ff6670e1a5ab3b5f0e6ce5bd7e992b6310
+dist/2024-07-26/clippy-beta-x86_64-apple-darwin.tar.xz=e4bc44ff13cfdd70f94c5efe86e93de041599e570c19611141c00700a656b40c
+dist/2024-07-26/clippy-beta-x86_64-pc-windows-gnu.tar.gz=1b1aff83773de4dd972734cb03209eccfc3793f442a1a5dea51f451ca34cd1cc
+dist/2024-07-26/clippy-beta-x86_64-pc-windows-gnu.tar.xz=71c357ff694cd954314c47e3bd458465453c65e6022799827b8560ecae16fdc8
+dist/2024-07-26/clippy-beta-x86_64-pc-windows-msvc.tar.gz=d4759993b9659ad8354d3fdf858cf99efebdf8202442505e11b55d24a54b31a0
+dist/2024-07-26/clippy-beta-x86_64-pc-windows-msvc.tar.xz=e29eaea7b7f2e54b9285a2216f5b85440313650090c268048ce9e830e007fa92
+dist/2024-07-26/clippy-beta-x86_64-unknown-freebsd.tar.gz=4009c19d557156e63ad7123d27264650d046cd20e723ec6cc8ffdb3fc1d3b8b1
+dist/2024-07-26/clippy-beta-x86_64-unknown-freebsd.tar.xz=9622117651423c53c35f69cb3087a5294cca098ac93aeb7c18bcab035a1e69ef
+dist/2024-07-26/clippy-beta-x86_64-unknown-illumos.tar.gz=a88fd4b3e30faaecf270936422e254a25ff5dba93b08ca4003a9978ee80d0838
+dist/2024-07-26/clippy-beta-x86_64-unknown-illumos.tar.xz=f391b26009b7089f3d49d2f3409bb4e02e3de0700284727d2d26e7062bb18011
+dist/2024-07-26/clippy-beta-x86_64-unknown-linux-gnu.tar.gz=e467501c65651d519ae9a489e821e7d5dc82fdbeb2da2d4c75f093e1b898abd6
+dist/2024-07-26/clippy-beta-x86_64-unknown-linux-gnu.tar.xz=9dcbd07899af86db3c101275ab0f2fd3b5b0c43d4a92c5b5be05f0e4500d7535
+dist/2024-07-26/clippy-beta-x86_64-unknown-linux-musl.tar.gz=c2a30c78a6ab64d1655651fdd5c7f970dadcd6dfd1a585d130bd890190fe67f6
+dist/2024-07-26/clippy-beta-x86_64-unknown-linux-musl.tar.xz=05c2a38fa5bca162e365218670a7c195ebd9b3491d14464282a273dfe93b0ad7
+dist/2024-07-26/clippy-beta-x86_64-unknown-netbsd.tar.gz=75ee727a80119a810193519535f962721d547297feb9b5597b397e59277de701
+dist/2024-07-26/clippy-beta-x86_64-unknown-netbsd.tar.xz=002b726868a14df5ea31fe8eb75fae24660fb1cfad73591e86f9179dd1bb2dc4
+dist/2024-07-30/rustfmt-nightly-aarch64-apple-darwin.tar.gz=d3bb2f1fa20555373189caa7e58a8e3071c7ea6e7059bab15d6dd52dfef56c4f
+dist/2024-07-30/rustfmt-nightly-aarch64-apple-darwin.tar.xz=ba0019eb0766dd438069988156994270959c875b010afce0f455540a0bb2ee2f
+dist/2024-07-30/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz=24bbbe80a998b78f04c15d82fcef9498315b1b8d0ddabeeb5b6729b14bafbf70
+dist/2024-07-30/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz=cc396d3639c7213ab6442dc79ab6a1a42bb17910aa6d27046cc89ebeb6973231
+dist/2024-07-30/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz=e6dc772727a20920607923ff5a99526054e6244c40cc6c97fe68db58896de6fc
+dist/2024-07-30/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz=eec95e09ec7bd64ab8a47e7311103f5bc58aa3499edcba052699686315f8441a
+dist/2024-07-30/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz=fef3eb7d5dee7458daacfba9b97d579868864267fcdc85334f02384683ce0c17
+dist/2024-07-30/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz=44f376f4d9e84645373b4cbfe17678c288a71b92622ab4091ca7b82ed6a21b57
+dist/2024-07-30/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz=5c17927f12149fa605e3f671d25ac456d1d2bdac796b5ca466bfa7fb8688d224
+dist/2024-07-30/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz=04783b1a2efc10696b0d32fde7c63437e17548d38b2272f928f28915107f4f18
+dist/2024-07-30/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz=1365d93efc4391f189726e69c7a968c8debb50411f29404da42d19bc9e053937
+dist/2024-07-30/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz=db344c9f6d31ac5a2efc839cbb886c312534e9b1fe4b116629eaca74f79c316d
+dist/2024-07-30/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz=049a2b666956a56365661d944a0fc030673bec5578062ddaad104363f4ff1031
+dist/2024-07-30/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz=32d3bc08316c0cfc3c1ea689ccdc80978f744864c048863b9d51ae59b6e2f0c2
+dist/2024-07-30/rustfmt-nightly-i686-pc-windows-gnu.tar.gz=bc33833cd41bf5ac36730fc9d3ef9c87643d42b8e711de286138962fb5fac4a5
+dist/2024-07-30/rustfmt-nightly-i686-pc-windows-gnu.tar.xz=feffb4527ad627a0239d788272edac9a0fbec704de3a67aabbd8a9cbb95d4fe3
+dist/2024-07-30/rustfmt-nightly-i686-pc-windows-msvc.tar.gz=0ffb98b839f6640ac75e094cbb469a06f2e45f51ced01efbeb51a3fba866a048
+dist/2024-07-30/rustfmt-nightly-i686-pc-windows-msvc.tar.xz=d229ea866bf4d6c2d8d748630146c7bccedb4ba5a17056fbdc4558baf976f067
+dist/2024-07-30/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz=431de55efb797c75d8e440ba3da9ac70a04cccfc56b4e22b80b6488360915f90
+dist/2024-07-30/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz=e9e4eac4205014b6b61c759a8326f7a5e44e8ff05726510a8bbefd656f78e97c
+dist/2024-07-30/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz=99381507f8fc42d9bd00c545dd7ef4734e364a4e994d02bae148f78b94f50ab5
+dist/2024-07-30/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz=6e2cd283d9370beb9c208bd823ac2433df500adf7e70d8acfe5a261e62be2b4a
+dist/2024-07-30/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.gz=761a9733f53ecba343139bd1c028a66242824ef8f7c54ae63e0aaf0e77cabcf9
+dist/2024-07-30/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.xz=c2973a99220588ea78b7a052861c345f01254073d6bb77e96982b12382907e2b
+dist/2024-07-30/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz=4288ee8fc5f650b3d5c24be2ea114e133d3bad8ddf7e2211cdb72151410c755a
+dist/2024-07-30/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz=2a31e1f211a26f6798acd4c779827bfa4e1ac4d77103a48be74617e5af1661a1
+dist/2024-07-30/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz=9598edeb1ff5eff934f1e4783b3ed263babb53d3513564ccccf453dada872ba1
+dist/2024-07-30/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz=eb5392fce8ee4a016406efba546366ff91d4db8cda94dd131dbda70c553b6c06
+dist/2024-07-30/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz=0e9c55ee790eed653eda7b913e64d344ccbbe1681321377186d1e4882dc93bfc
+dist/2024-07-30/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz=c9a0b3eddac707c4e0c1cdc754d2821845e5f4bdcbd001b71d7287fe851cc44b
+dist/2024-07-30/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz=99c264f806d4a6a1288a9cc7f28e178102520ebe4728fb0da3f8142c1d6720e0
+dist/2024-07-30/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz=3f1835460dbf17a3dbf47f2772e182ebf6337fd6a946a033f9700fb38140eda6
+dist/2024-07-30/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz=385224b95c56de8598dd5b4eeb48d7d7a8eb920825c55bb4d7be54142d7e2857
+dist/2024-07-30/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz=535220608ee858d46746c8de4c1e58f4f675061517b6b06c8af47004d5291f85
+dist/2024-07-30/rustfmt-nightly-x86_64-apple-darwin.tar.gz=aa19f1856befff101bcb433049e923486d7bc1a056638e478651936572e7e3bf
+dist/2024-07-30/rustfmt-nightly-x86_64-apple-darwin.tar.xz=2ed04cf9fddeafbb83d82988e00d3b7f5ae9382468ce1093cbb110bf46b04711
+dist/2024-07-30/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz=962dea60de3ac68a573f088f9c1b003816ce93f9088df15fe8cf7771a3abdc73
+dist/2024-07-30/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz=72f7b787644bd9008b13018512c0b09a425c15a337821dc9bded9ab7211c61de
+dist/2024-07-30/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz=1096ba25a23461eed84804584eb9ffdff780e2c737cc9dce1e8929419dfd645b
+dist/2024-07-30/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz=854b9e410e65b953ab71f356bd5b618679aa7c1f5a3de7f81ec388720ed04f60
+dist/2024-07-30/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz=03b4ab410c70fee3daa7a577c311b29344158a7d35ea87627233cb6165191338
+dist/2024-07-30/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz=d755700cc17416c4488db2d582250b5ec329fc0c2b94e9db0e6688ca30a7316c
+dist/2024-07-30/rustfmt-nightly-x86_64-unknown-illumos.tar.gz=b7448089c61c2f0a427416cd7521130c31a98c52e435bd0d04d6aad72d765ba6
+dist/2024-07-30/rustfmt-nightly-x86_64-unknown-illumos.tar.xz=cb3f479897032ff9ec5e06913e8e4374ce46af7f8a9030299c7b0cab2dab2005
+dist/2024-07-30/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz=0c7dbff79d04218a7ba3f5992f67d25043bc5f348038f37ab7385cbc4d0df00d
+dist/2024-07-30/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz=4f62cbc75a81d57748111a915ebb20f561f403c1b695141780d50c398b186fa6
+dist/2024-07-30/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz=e5e8b07ae7ba0e1f526828a10f2515a68b0ed6023eed25e3bb10b80e21e8db76
+dist/2024-07-30/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz=424ec90c59fca7e21b302efd7c6c7f7dbc5dcadd1afbb15e90efea38ea8a19cf
+dist/2024-07-30/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz=f22576893113958f6caabcf3ab3e38287fea010c1809a8bb1197220d6660ea4e
+dist/2024-07-30/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz=5e85141abe2a3c537cb4171c60cff5bdb11f075aa79212e0a958081d4648aec6
+dist/2024-07-30/rustc-nightly-aarch64-apple-darwin.tar.gz=f793e4645be9461fae09e82710bcfdfc6d749735be202f2e2cd6c2c643bb8925
+dist/2024-07-30/rustc-nightly-aarch64-apple-darwin.tar.xz=e42f52cc5a865ab92321b97aaeff4d39cbaad1a5b60a9a77de9f42e3b3231d21
+dist/2024-07-30/rustc-nightly-aarch64-pc-windows-msvc.tar.gz=0258ba5bf957d190ef3a384c5451ebbe8406c195a29b3a7ee2a4c48e0514f203
+dist/2024-07-30/rustc-nightly-aarch64-pc-windows-msvc.tar.xz=788b7e9239562f43c0d96cfd66f543604eef1c9b40d22898c456fade608e9c31
+dist/2024-07-30/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz=94187df22d7b96a5c39c5c9a078f566b80d392abfd2a5d7059b836cfa0c446e1
+dist/2024-07-30/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz=ca1381c6de1a96f32a30736c28aa196f7e653b4f57f01ffe2db52fe238a9f202
+dist/2024-07-30/rustc-nightly-aarch64-unknown-linux-musl.tar.gz=1c72596862a133003f68590a8ae09bf6ab25a5f9667a6d245eafede1ebd8f450
+dist/2024-07-30/rustc-nightly-aarch64-unknown-linux-musl.tar.xz=de0c216f229301bc88690b10b8f063b8e389915503980973b91bfe17b1fb6eda
+dist/2024-07-30/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz=e00283a7ee9a702446456feb0156f1d1fc738fd013983f15c456fcafb8294309
+dist/2024-07-30/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz=03fab128bc3756676c645f637edc5051f8096b00780d8ef4de7a85b3f248933a
+dist/2024-07-30/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz=105e06c0ca69b4a700980f2a588f831c23a9a9253268bd652110328b99918cb1
+dist/2024-07-30/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz=0da27ffe5504a03923ae5858b69cdd6eb276e6bd2bfb504bcf13ebdda654316b
+dist/2024-07-30/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz=edb1bec402f3799e05fd3e31f30763e7266d2e062e410af8eab7636440da272c
+dist/2024-07-30/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz=638a09ecfe0b66391ce6802e3e15bf15462aca1c8cfb2a49b948ec69eda0575c
+dist/2024-07-30/rustc-nightly-i686-pc-windows-gnu.tar.gz=456683fa10703ba8249f8b1735293c79edac0c32aec60c1a91315fb41c8e5ecc
+dist/2024-07-30/rustc-nightly-i686-pc-windows-gnu.tar.xz=fd5d9a7bf543d3c61ca85340961d5e17b42b37c35fe45c666c2a0e125548f42e
+dist/2024-07-30/rustc-nightly-i686-pc-windows-msvc.tar.gz=2b75a4e15d1f98f123ef74aecab3570296aeb7e35f18548a2b3d1735e01b06e0
+dist/2024-07-30/rustc-nightly-i686-pc-windows-msvc.tar.xz=1163178e95180725bd31b7dabf1e9a9788a8e7cc576dd53148cfec32443e64a1
+dist/2024-07-30/rustc-nightly-i686-unknown-linux-gnu.tar.gz=0aad8dd79beca26278e1c1847dde17ee22ae64b78f2b02be65e12bc126de699b
+dist/2024-07-30/rustc-nightly-i686-unknown-linux-gnu.tar.xz=a548e90fbce90c26b6700cff7964d72c7e959a6f317e891db4f91ce7cd187c41
+dist/2024-07-30/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz=654ec9040afb20d660603adcd31824efeacef0ae2d48d342bb9504bd2f723453
+dist/2024-07-30/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz=998407bc1303eecb1ef4c6b14862ffdf31fb0cf991f5d169a822a23627b29352
+dist/2024-07-30/rustc-nightly-loongarch64-unknown-linux-musl.tar.gz=5b4febf9a1802c2c756ef8a7693a9cfd83bf95284d79d9f9b9dd265234d6aebc
+dist/2024-07-30/rustc-nightly-loongarch64-unknown-linux-musl.tar.xz=dbc2a6417fabcfb37f4fa42d50391c1cb29f18d1771321088c08afdf0a0e4809
+dist/2024-07-30/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz=2befcab4aa3e31064b87e4696aa2f1e76bd9c24067eb1921feb7f6497d58338c
+dist/2024-07-30/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz=508a3c1241507a53a0d6b27df2171eaf0a4df903773b5592f005ee4d39d91287
+dist/2024-07-30/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz=c4e8da248306be350f7a89b2522e976a12ab89d5ae2e19157ed3b148e3948c50
+dist/2024-07-30/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz=5858e1cf6371f25ba3c381e07ba6f4551c2a13516011fc10dbdafc4caf1bff93
+dist/2024-07-30/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz=3639bbb7aac353772171dcfaecd589352de3fd8cc7395e7628d7590830034af4
+dist/2024-07-30/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz=3cad5f0b74fc3f5be70cf496c93054c50e8a3f92cfc894a2febfbecc382dcb55
+dist/2024-07-30/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz=437fc8b815c09a3c5159735d9fec0e5d8dd64416149cb77c13a16863e6636412
+dist/2024-07-30/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz=7bc2917e7816f7df1bc7faeda28010d247c923aba412b5ec1cc9c6757eec37d9
+dist/2024-07-30/rustc-nightly-s390x-unknown-linux-gnu.tar.gz=603e391a14c26a51f4f02020b5abbd307d29476fdc0689e5bf9570f2e6ac69a8
+dist/2024-07-30/rustc-nightly-s390x-unknown-linux-gnu.tar.xz=d04ea4e522cf1ecaa6b2f3edcb32155142378bc648aa159a574838ed2d58b794
+dist/2024-07-30/rustc-nightly-x86_64-apple-darwin.tar.gz=0ed639da01e58645eb33a75e020d57c58c92651d817e89574cb67bae5b298d35
+dist/2024-07-30/rustc-nightly-x86_64-apple-darwin.tar.xz=b4010f38396e7b8acd67cf2234c94ede11cf78a226a134c809d504e594037311
+dist/2024-07-30/rustc-nightly-x86_64-pc-windows-gnu.tar.gz=7ec8aba7a7581d59c7ceaffdd374852d08b17bc7e02674c5bfd4f47f4a0aee39
+dist/2024-07-30/rustc-nightly-x86_64-pc-windows-gnu.tar.xz=41c3ba0543220e11bc53282dd7d2a37acd6450a59683e1c83d2150dc798cfba7
+dist/2024-07-30/rustc-nightly-x86_64-pc-windows-msvc.tar.gz=67e5d75dda47c587a4be517db547354d1da0228110b7d5488d8822a7ef7cda20
+dist/2024-07-30/rustc-nightly-x86_64-pc-windows-msvc.tar.xz=4b5f0c4101a783dd313c0cd1435d7eccfeac97452afaeaf42ba975805541dc74
+dist/2024-07-30/rustc-nightly-x86_64-unknown-freebsd.tar.gz=09e12b5003969b768b5c06b3e3b41a64429e28c32790ff28c12b8c5814f350c0
+dist/2024-07-30/rustc-nightly-x86_64-unknown-freebsd.tar.xz=a4b3b402cf4beb3e7c7b9b6620f34d045ef42261514ae7d8483d3790d1dfd88a
+dist/2024-07-30/rustc-nightly-x86_64-unknown-illumos.tar.gz=c344d0c95aadac0e5e0100743b80768c9d0cd76b123ab07e6387ad1ea3e3efba
+dist/2024-07-30/rustc-nightly-x86_64-unknown-illumos.tar.xz=ac0a79660227fe163c796e6b816596299f6d8b32ba008ce30cde492709efb7c0
+dist/2024-07-30/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz=4090ff8086317662d3def1bc92d51e6f2decd2c64f4b6ede38604fd5029d3d02
+dist/2024-07-30/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz=e665bd4e3763b456576eaa45bcf188648cc6e6443ecdff8ef91a5c7649cbfd25
+dist/2024-07-30/rustc-nightly-x86_64-unknown-linux-musl.tar.gz=4fa994e08274599ae3bceb9310c584be89d11f231aad3e8fc1e2d6a6ddbb77bf
+dist/2024-07-30/rustc-nightly-x86_64-unknown-linux-musl.tar.xz=bd8d53403bf6337782bffc3050a46887fbe2568c850809c5b32c8d84492d2ee9
+dist/2024-07-30/rustc-nightly-x86_64-unknown-netbsd.tar.gz=606a430036fdda0b92dd4a4cb99830881389693e6ed02a01ddd51eaecdfdf463
+dist/2024-07-30/rustc-nightly-x86_64-unknown-netbsd.tar.xz=fa34273b20336b8b373f686c88ee297033f635895ad225a2ca5271b6da3d7dea
\ No newline at end of file
diff --git a/src/tools/build-manifest/src/checksum.rs b/src/tools/build-manifest/src/checksum.rs
index c019c7a2f7a..c69b4180d92 100644
--- a/src/tools/build-manifest/src/checksum.rs
+++ b/src/tools/build-manifest/src/checksum.rs
@@ -1,6 +1,3 @@
-use crate::manifest::{FileHash, Manifest};
-use rayon::prelude::*;
-use sha2::{Digest, Sha256};
 use std::collections::{HashMap, HashSet};
 use std::error::Error;
 use std::fs::File;
@@ -9,6 +6,11 @@ use std::path::{Path, PathBuf};
 use std::sync::Mutex;
 use std::time::Instant;
 
+use rayon::prelude::*;
+use sha2::{Digest, Sha256};
+
+use crate::manifest::{FileHash, Manifest};
+
 pub(crate) struct Checksums {
     cache_path: Option<PathBuf>,
     collected: Mutex<HashMap<PathBuf, String>>,
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index e0bea5f053d..2b263f848e8 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -4,13 +4,13 @@ mod checksum;
 mod manifest;
 mod versions;
 
+use std::collections::{BTreeMap, HashSet};
+use std::path::{Path, PathBuf};
+use std::{env, fs};
+
 use crate::checksum::Checksums;
 use crate::manifest::{Component, Manifest, Package, Rename, Target};
 use crate::versions::{PkgType, Versions};
-use std::collections::{BTreeMap, HashSet};
-use std::env;
-use std::fs;
-use std::path::{Path, PathBuf};
 
 static HOSTS: &[&str] = &[
     "aarch64-apple-darwin",
@@ -141,6 +141,7 @@ static TARGETS: &[&str] = &[
     "riscv64gc-unknown-hermit",
     "riscv64gc-unknown-none-elf",
     "riscv64gc-unknown-linux-gnu",
+    "riscv64gc-unknown-linux-musl",
     "s390x-unknown-linux-gnu",
     "sparc64-unknown-linux-gnu",
     "sparcv9-sun-solaris",
diff --git a/src/tools/build-manifest/src/manifest.rs b/src/tools/build-manifest/src/manifest.rs
index 6fa4f83e415..695a8f5d4e7 100644
--- a/src/tools/build-manifest/src/manifest.rs
+++ b/src/tools/build-manifest/src/manifest.rs
@@ -1,9 +1,11 @@
-use crate::versions::PkgType;
-use crate::Builder;
-use serde::{Serialize, Serializer};
 use std::collections::BTreeMap;
 use std::path::{Path, PathBuf};
 
+use serde::{Serialize, Serializer};
+
+use crate::versions::PkgType;
+use crate::Builder;
+
 #[derive(Serialize)]
 #[serde(rename_all = "kebab-case")]
 pub(crate) struct Manifest {
diff --git a/src/tools/build-manifest/src/versions.rs b/src/tools/build-manifest/src/versions.rs
index 233a2670ed2..495cab582eb 100644
--- a/src/tools/build-manifest/src/versions.rs
+++ b/src/tools/build-manifest/src/versions.rs
@@ -1,9 +1,10 @@
-use anyhow::Error;
-use flate2::read::GzDecoder;
 use std::collections::HashMap;
 use std::fs::File;
 use std::io::Read;
 use std::path::{Path, PathBuf};
+
+use anyhow::Error;
+use flate2::read::GzDecoder;
 use tar::Archive;
 use xz2::read::XzDecoder;
 
@@ -100,9 +101,10 @@ impl PkgType {
     }
 
     pub(crate) fn targets(&self) -> &[&str] {
-        use crate::{HOSTS, MINGW, TARGETS};
         use PkgType::*;
 
+        use crate::{HOSTS, MINGW, TARGETS};
+
         match self {
             Rust => HOSTS, // doesn't matter in practice, but return something to avoid panicking
             Rustc => HOSTS,
diff --git a/src/tools/build_helper/src/git.rs b/src/tools/build_helper/src/git.rs
index 8be38dc855f..da84569c778 100644
--- a/src/tools/build_helper/src/git.rs
+++ b/src/tools/build_helper/src/git.rs
@@ -1,5 +1,5 @@
-use std::process::Stdio;
-use std::{path::Path, process::Command};
+use std::path::Path;
+use std::process::{Command, Stdio};
 
 pub struct GitConfig<'a> {
     pub git_repository: &'a str,
diff --git a/src/tools/bump-stage0/src/main.rs b/src/tools/bump-stage0/src/main.rs
index bb06e113c0e..f8c75ca7226 100644
--- a/src/tools/bump-stage0/src/main.rs
+++ b/src/tools/bump-stage0/src/main.rs
@@ -4,7 +4,6 @@ use anyhow::{Context, Error};
 use build_helper::stage0_parser::{parse_stage0_file, Stage0Config, VersionMetadata};
 use curl::easy::Easy;
 use indexmap::IndexMap;
-use std::collections::HashMap;
 
 const PATH: &str = "src/stage0";
 const COMPILER_COMPONENTS: &[&str] = &["rustc", "rust-std", "cargo", "clippy-preview"];
@@ -216,13 +215,13 @@ enum Channel {
 #[derive(Debug, serde::Serialize, serde::Deserialize)]
 struct Manifest {
     date: String,
-    pkg: HashMap<String, ManifestPackage>,
+    pkg: IndexMap<String, ManifestPackage>,
 }
 
 #[derive(Debug, serde::Serialize, serde::Deserialize)]
 struct ManifestPackage {
     version: String,
-    target: HashMap<String, ManifestTargetPackage>,
+    target: IndexMap<String, ManifestTargetPackage>,
 }
 
 #[derive(Debug, serde::Serialize, serde::Deserialize)]
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject b5d44db1daf0469b227a6211b987162a39a5473
+Subproject 0d8d22f83b066503f6b2b755925197e959e58b4
diff --git a/src/tools/cargotest/main.rs b/src/tools/cargotest/main.rs
index a5d2ffb1572..4c57683806e 100644
--- a/src/tools/cargotest/main.rs
+++ b/src/tools/cargotest/main.rs
@@ -1,7 +1,6 @@
-use std::env;
-use std::fs;
 use std::path::{Path, PathBuf};
 use std::process::Command;
+use std::{env, fs};
 
 struct Test {
     repo: &'static str,
diff --git a/src/tools/clippy/.cargo/config.toml b/src/tools/clippy/.cargo/config.toml
index 7afdd068a99..ce07290d1e1 100644
--- a/src/tools/clippy/.cargo/config.toml
+++ b/src/tools/clippy/.cargo/config.toml
@@ -13,6 +13,13 @@ target-dir = "target"
 
 [unstable]
 binary-dep-depinfo = true
+profile-rustflags = true
 
 [profile.dev]
 split-debuginfo = "unpacked"
+
+# Add back the containing directory of the packages we have to refer to using --manifest-path
+[profile.dev.package.clippy_dev]
+rustflags = ["--remap-path-prefix", "=clippy_dev"]
+[profile.dev.package.lintcheck]
+rustflags = ["--remap-path-prefix", "=lintcheck"]
diff --git a/src/tools/clippy/.github/workflows/clippy.yml b/src/tools/clippy/.github/workflows/clippy.yml
index 06bf3b6fdbf..0a0538490cc 100644
--- a/src/tools/clippy/.github/workflows/clippy.yml
+++ b/src/tools/clippy/.github/workflows/clippy.yml
@@ -25,6 +25,7 @@ env:
   CARGO_TARGET_DIR: '${{ github.workspace }}/target'
   NO_FMT_TEST: 1
   CARGO_INCREMENTAL: 0
+  RUSTFLAGS: -D warnings
 
 concurrency:
   # For a given workflow, if we push to the same PR, cancel all previous builds on that PR.
@@ -47,25 +48,25 @@ jobs:
 
     # Run
     - name: Build
-      run: cargo build --tests --features deny-warnings,internal
+      run: cargo build --tests --features internal
 
     - name: Test
-      run: cargo test --features deny-warnings,internal
+      run: cargo test --features internal
 
     - name: Test clippy_lints
-      run: cargo test --features deny-warnings,internal
+      run: cargo test --features internal
       working-directory: clippy_lints
 
     - name: Test clippy_utils
-      run: cargo test --features deny-warnings
+      run: cargo test
       working-directory: clippy_utils
 
     - name: Test rustc_tools_util
-      run: cargo test --features deny-warnings
+      run: cargo test
       working-directory: rustc_tools_util
 
     - name: Test clippy_dev
-      run: cargo test --features deny-warnings
+      run: cargo test
       working-directory: clippy_dev
 
     - name: Test clippy-driver
diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml
index 1f4bec92918..10e18e84c89 100644
--- a/src/tools/clippy/.github/workflows/clippy_bors.yml
+++ b/src/tools/clippy/.github/workflows/clippy_bors.yml
@@ -11,6 +11,7 @@ env:
   CARGO_TARGET_DIR: '${{ github.workspace }}/target'
   NO_FMT_TEST: 1
   CARGO_INCREMENTAL: 0
+  RUSTFLAGS: -D warnings
 
 concurrency:
   # For a given workflow, if we push to the same branch, cancel all previous builds on that branch.
@@ -85,34 +86,34 @@ jobs:
 
     # Run
     - name: Build
-      run: cargo build --tests --features deny-warnings,internal
+      run: cargo build --tests --features internal
 
     - name: Test
       if: matrix.host == 'x86_64-unknown-linux-gnu'
-      run: cargo test --features deny-warnings,internal
+      run: cargo test --features internal
 
     - name: Test
       if: matrix.host != 'x86_64-unknown-linux-gnu'
-      run: cargo test --features deny-warnings,internal -- --skip dogfood
+      run: cargo test --features internal -- --skip dogfood
 
     - name: Test clippy_lints
-      run: cargo test --features deny-warnings,internal
+      run: cargo test --features internal
       working-directory: clippy_lints
 
     - name: Test clippy_utils
-      run: cargo test --features deny-warnings
+      run: cargo test
       working-directory: clippy_utils
 
     - name: Test clippy_config
-      run: cargo test --features deny-warnings
+      run: cargo test
       working-directory: clippy_config
 
     - name: Test rustc_tools_util
-      run: cargo test --features deny-warnings
+      run: cargo test
       working-directory: rustc_tools_util
 
     - name: Test clippy_dev
-      run: cargo test --features deny-warnings
+      run: cargo test
       working-directory: clippy_dev
 
     - name: Test clippy-driver
diff --git a/src/tools/clippy/.github/workflows/clippy_dev.yml b/src/tools/clippy/.github/workflows/clippy_dev.yml
index 37f18a4c087..cf0a8bde202 100644
--- a/src/tools/clippy/.github/workflows/clippy_dev.yml
+++ b/src/tools/clippy/.github/workflows/clippy_dev.yml
@@ -16,6 +16,7 @@ on:
 env:
   RUST_BACKTRACE: 1
   CARGO_INCREMENTAL: 0
+  RUSTFLAGS: -D warnings
 
 jobs:
   clippy_dev:
@@ -28,7 +29,7 @@ jobs:
 
     # Run
     - name: Build
-      run: cargo build --features deny-warnings
+      run: cargo build
       working-directory: clippy_dev
 
     - name: Test update_lints
@@ -38,6 +39,8 @@ jobs:
       run: cargo dev fmt --check
 
     - name: Test cargo dev new lint
+      env:
+        RUSTFLAGS: -A unused-imports
       run: |
         cargo dev new_lint --name new_early_pass --pass early
         cargo dev new_lint --name new_late_pass --pass late
diff --git a/src/tools/clippy/.github/workflows/lintcheck.yml b/src/tools/clippy/.github/workflows/lintcheck.yml
index 6a5139b6dc0..3cbda0b3824 100644
--- a/src/tools/clippy/.github/workflows/lintcheck.yml
+++ b/src/tools/clippy/.github/workflows/lintcheck.yml
@@ -58,7 +58,7 @@ jobs:
 
     - name: Run lintcheck
       if: steps.cache-json.outputs.cache-hit != 'true'
-      run: ./target/debug/lintcheck --format json --warn-all --crates-toml ./lintcheck/ci_crates.toml
+      run: ./target/debug/lintcheck --format json --all-lints --crates-toml ./lintcheck/ci_crates.toml
 
     - name: Upload base JSON
       uses: actions/upload-artifact@v4
@@ -86,7 +86,7 @@ jobs:
       run: cargo build --manifest-path=lintcheck/Cargo.toml
 
     - name: Run lintcheck
-      run: ./target/debug/lintcheck --format json --warn-all --crates-toml ./lintcheck/ci_crates.toml
+      run: ./target/debug/lintcheck --format json --all-lints --crates-toml ./lintcheck/ci_crates.toml
 
     - name: Upload head JSON
       uses: actions/upload-artifact@v4
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 60c03b03d9b..fddc2fd994e 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -5830,6 +5830,7 @@ Released 2018-09-13
 [`result_unit_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unit_err
 [`result_unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unwrap_used
 [`return_self_not_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#return_self_not_must_use
+[`reverse_range_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#reverse_range_loop
 [`reversed_empty_ranges`]: https://rust-lang.github.io/rust-clippy/master/index.html#reversed_empty_ranges
 [`same_functions_in_if_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_functions_in_if_condition
 [`same_item_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push
@@ -5998,6 +5999,7 @@ Released 2018-09-13
 [`unused_io_amount`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount
 [`unused_label`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_label
 [`unused_peekable`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_peekable
+[`unused_result_ok`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_result_ok
 [`unused_rounding`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_rounding
 [`unused_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_self
 [`unused_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index bb4dc97e748..78409c7a09e 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -30,7 +30,7 @@ color-print = "0.3.4"
 anstream = "0.6.0"
 
 [dev-dependencies]
-ui_test = "0.24"
+ui_test = "0.25"
 regex = "1.5.5"
 toml = "0.7.3"
 walkdir = "2.3"
@@ -51,7 +51,6 @@ tokio = { version = "1", features = ["io-util"] }
 rustc_tools_util = "0.3.0"
 
 [features]
-deny-warnings = ["clippy_lints/deny-warnings"]
 integration = ["tempfile"]
 internal = ["clippy_lints/internal", "tempfile"]
 
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index fb717a2c166..e3d550b1466 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -364,7 +364,7 @@ Suppress lints whenever the suggested change would cause breakage for other crat
 
 
 ## `await-holding-invalid-types`
-
+The list of types which may not be held across an await point.
 
 **Default Value:** `[]`
 
@@ -668,6 +668,8 @@ crate. For example, `pub(crate)` items.
 ## `msrv`
 The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml`
 
+**Default Value:** `current version`
+
 ---
 **Affected lints:**
 * [`allow_attributes`](https://rust-lang.github.io/rust-clippy/master/index.html#allow_attributes)
@@ -862,6 +864,8 @@ The maximum number of lines a function or method can have
 The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by
 reference. By default there is no limit
 
+**Default Value:** `target_pointer_width * 2`
+
 ---
 **Affected lints:**
 * [`trivially_copy_pass_by_ref`](https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref)
diff --git a/src/tools/clippy/clippy_config/Cargo.toml b/src/tools/clippy/clippy_config/Cargo.toml
index e1b2edc8a6f..d5b28e25323 100644
--- a/src/tools/clippy/clippy_config/Cargo.toml
+++ b/src/tools/clippy/clippy_config/Cargo.toml
@@ -6,6 +6,7 @@ edition = "2021"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
+itertools = "0.12"
 rustc-semver = "1.1"
 serde = { version = "1.0", features = ["derive"] }
 toml = "0.7.3"
@@ -13,9 +14,6 @@ toml = "0.7.3"
 [dev-dependencies]
 walkdir = "2.3"
 
-[features]
-deny-warnings = []
-
 [package.metadata.rust-analyzer]
 # This crate uses #[feature(rustc_private)]
 rustc_private = true
diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs
index 63140a36875..4c2a8255d6b 100644
--- a/src/tools/clippy/clippy_config/src/conf.rs
+++ b/src/tools/clippy/clippy_config/src/conf.rs
@@ -123,7 +123,8 @@ macro_rules! define_Conf {
         $(#[doc = $doc:literal])+
         $(#[conf_deprecated($dep:literal, $new_conf:ident)])?
         $(#[default_text = $default_text:expr])?
-        ($name:ident: $ty:ty = $default:expr),
+        $(#[lints($($for_lints:ident),* $(,)?)])?
+        $name:ident: $ty:ty = $default:expr,
     )*) => {
         /// Clippy lint configuration
         pub struct Conf {
@@ -201,29 +202,128 @@ macro_rules! define_Conf {
         }
 
         pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
-            let mut sorted = vec![
-                $(
-                    {
-                        let deprecation_reason = wrap_option!($($dep)?);
-
-                        ClippyConfiguration::new(
-                            stringify!($name),
-                            default_text!(defaults::$name() $(, $default_text)?),
-                            concat!($($doc, '\n',)*),
-                            deprecation_reason,
-                        )
-                    },
-                )+
-            ];
-            sorted.sort_by(|a, b| a.name.cmp(&b.name));
-            sorted
+            vec![$(
+                ClippyConfiguration {
+                    name: stringify!($name).replace('_', "-"),
+                    default: default_text!(defaults::$name() $(, $default_text)?),
+                    lints: &[$($(stringify!($for_lints)),*)?],
+                    doc: concat!($($doc, '\n',)*),
+                    deprecation_reason: wrap_option!($($dep)?)
+                },
+            )*]
         }
     };
 }
 
 define_Conf! {
-    /// Lint: ARITHMETIC_SIDE_EFFECTS.
+    /// Which crates to allow absolute paths from
+    #[lints(absolute_paths)]
+    absolute_paths_allowed_crates: FxHashSet<String> = FxHashSet::default(),
+    /// The maximum number of segments a path can have before being linted, anything above this will
+    /// be linted.
+    #[lints(absolute_paths)]
+    absolute_paths_max_segments: u64 = 2,
+    /// Whether to accept a safety comment to be placed above the attributes for the `unsafe` block
+    #[lints(undocumented_unsafe_blocks)]
+    accept_comment_above_attributes: bool = true,
+    /// Whether to accept a safety comment to be placed above the statement containing the `unsafe` block
+    #[lints(undocumented_unsafe_blocks)]
+    accept_comment_above_statement: bool = true,
+    /// Don't lint when comparing the result of a modulo operation to zero.
+    #[lints(modulo_arithmetic)]
+    allow_comparison_to_zero: bool = true,
+    /// Whether `dbg!` should be allowed in test functions or `#[cfg(test)]`
+    #[lints(dbg_macro)]
+    allow_dbg_in_tests: bool = false,
+    /// Whether `expect` should be allowed in test functions or `#[cfg(test)]`
+    #[lints(expect_used)]
+    allow_expect_in_tests: bool = false,
+    /// Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)`
+    #[lints(uninlined_format_args)]
+    allow_mixed_uninlined_format_args: bool = true,
+    /// Whether to allow `r#""#` when `r""` can be used
+    #[lints(unnecessary_raw_string_hashes)]
+    allow_one_hash_in_raw_strings: bool = false,
+    /// Whether `panic` should be allowed in test functions or `#[cfg(test)]`
+    #[lints(panic)]
+    allow_panic_in_tests: bool = false,
+    /// Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]`
+    #[lints(print_stderr, print_stdout)]
+    allow_print_in_tests: bool = false,
+    /// Whether to allow module inception if it's not public.
+    #[lints(module_inception)]
+    allow_private_module_inception: bool = false,
+    /// List of trait paths to ignore when checking renamed function parameters.
+    ///
+    /// #### Example
+    ///
+    /// ```toml
+    /// allow-renamed-params-for = [ "std::convert::From" ]
+    /// ```
+    ///
+    /// #### Noteworthy
+    ///
+    /// - By default, the following traits are ignored: `From`, `TryFrom`, `FromStr`
+    /// - `".."` can be used as part of the list to indicate that the configured values should be appended to the
+    /// default configuration of Clippy. By default, any configuration will replace the default value.
+    #[lints(renamed_function_params)]
+    allow_renamed_params_for: Vec<String> =
+        DEFAULT_ALLOWED_TRAITS_WITH_RENAMED_PARAMS.iter().map(ToString::to_string).collect(),
+    /// Whether `unwrap` should be allowed in test functions or `#[cfg(test)]`
+    #[lints(unwrap_used)]
+    allow_unwrap_in_tests: bool = false,
+    /// Whether `useless_vec` should ignore test functions or `#[cfg(test)]`
+    #[lints(useless_vec)]
+    allow_useless_vec_in_tests: bool = false,
+    /// Additional dotfiles (files or directories starting with a dot) to allow
+    #[lints(path_ends_with_ext)]
+    allowed_dotfiles: Vec<String> = Vec::default(),
+    /// A list of crate names to allow duplicates of
+    #[lints(multiple_crate_versions)]
+    allowed_duplicate_crates: FxHashSet<String> = FxHashSet::default(),
+    /// Allowed names below the minimum allowed characters. The value `".."` can be used as part of
+    /// the list to indicate, that the configured values should be appended to the default
+    /// configuration of Clippy. By default, any configuration will replace the default value.
+    #[lints(min_ident_chars)]
+    allowed_idents_below_min_chars: FxHashSet<String> =
+        DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string).collect(),
+    /// List of prefixes to allow when determining whether an item's name ends with the module's name.
+    /// If the rest of an item's name is an allowed prefix (e.g. item `ToFoo` or `to_foo` in module `foo`),
+    /// then don't emit a warning.
+    ///
+    /// #### Example
+    ///
+    /// ```toml
+    /// allowed-prefixes = [ "to", "from" ]
+    /// ```
+    ///
+    /// #### Noteworthy
+    ///
+    /// - By default, the following prefixes are allowed: `to`, `as`, `into`, `from`, `try_into` and `try_from`
+    /// - PascalCase variant is included automatically for each snake_case variant (e.g. if `try_into` is included,
+    ///   `TryInto` will also be included)
+    /// - Use `".."` as part of the list to indicate that the configured values should be appended to the
+    /// default configuration of Clippy. By default, any configuration will replace the default value
+    #[lints(module_name_repetitions)]
+    allowed_prefixes: Vec<String> = DEFAULT_ALLOWED_PREFIXES.iter().map(ToString::to_string).collect(),
+    /// The list of unicode scripts allowed to be used in the scope.
+    #[lints(disallowed_script_idents)]
+    allowed_scripts: Vec<String> = vec!["Latin".to_string()],
+    /// List of path segments allowed to have wildcard imports.
     ///
+    /// #### Example
+    ///
+    /// ```toml
+    /// allowed-wildcard-imports = [ "utils", "common" ]
+    /// ```
+    ///
+    /// #### Noteworthy
+    ///
+    /// 1. This configuration has no effects if used with `warn_on_all_wildcard_imports = true`.
+    /// 2. Paths with any segment that containing the word 'prelude'
+    /// are already allowed by default.
+    #[lints(wildcard_imports)]
+    allowed_wildcard_imports: FxHashSet<String> = FxHashSet::default(),
     /// Suppress checking of the passed type names in all types of operations.
     ///
     /// If a specific operation is desired, consider using `arithmetic_side_effects_allowed_binary` or `arithmetic_side_effects_allowed_unary` instead.
@@ -238,9 +338,8 @@ define_Conf! {
     ///
     /// A type, say `SomeType`, listed in this configuration has the same behavior of
     /// `["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`.
-    (arithmetic_side_effects_allowed: Vec<String> = <_>::default()),
-    /// Lint: ARITHMETIC_SIDE_EFFECTS.
-    ///
+    #[lints(arithmetic_side_effects)]
+    arithmetic_side_effects_allowed: Vec<String> = <_>::default(),
     /// Suppress checking of the passed type pair names in binary operations like addition or
     /// multiplication.
     ///
@@ -255,9 +354,8 @@ define_Conf! {
     /// ```toml
     /// arithmetic-side-effects-allowed-binary = [["SomeType" , "f32"], ["AnotherType", "*"]]
     /// ```
-    (arithmetic_side_effects_allowed_binary: Vec<[String; 2]> = <_>::default()),
-    /// Lint: ARITHMETIC_SIDE_EFFECTS.
-    ///
+    #[lints(arithmetic_side_effects)]
+    arithmetic_side_effects_allowed_binary: Vec<[String; 2]> = <_>::default(),
     /// Suppress checking of the passed type names in unary operations like "negation" (`-`).
     ///
     /// #### Example
@@ -265,298 +363,78 @@ define_Conf! {
     /// ```toml
     /// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"]
     /// ```
-    (arithmetic_side_effects_allowed_unary: Vec<String> = <_>::default()),
-    /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS, SINGLE_CALL_FN, NEEDLESS_PASS_BY_REF_MUT.
-    ///
+    #[lints(arithmetic_side_effects)]
+    arithmetic_side_effects_allowed_unary: Vec<String> = <_>::default(),
+    /// The maximum allowed size for arrays on the stack
+    #[lints(large_const_arrays, large_stack_arrays)]
+    array_size_threshold: u64 = 512_000,
     /// 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, MANUAL_PATTERN_CHAR_COMPARISON, ALLOW_ATTRIBUTES, ALLOW_ATTRIBUTES_WITHOUT_REASON, COLLAPSIBLE_MATCH.
-    ///
-    /// The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml`
-    #[default_text = ""]
-    (msrv: Msrv = Msrv::empty()),
+    #[lints(
+        box_collection,
+        enum_variant_names,
+        large_types_passed_by_value,
+        linkedlist,
+        needless_pass_by_ref_mut,
+        option_option,
+        rc_buffer,
+        rc_mutex,
+        redundant_allocation,
+        single_call_fn,
+        trivially_copy_pass_by_ref,
+        unnecessary_box_returns,
+        unnecessary_wraps,
+        unused_self,
+        upper_case_acronyms,
+        vec_box,
+        wrong_self_convention,
+    )]
+    avoid_breaking_exported_api: bool = true,
+    /// The list of types which may not be held across an await point.
+    #[lints(await_holding_invalid_type)]
+    await_holding_invalid_types: Vec<DisallowedPath> = Vec::new(),
     /// DEPRECATED LINT: BLACKLISTED_NAME.
     ///
     /// Use the Disallowed Names lint instead
     #[conf_deprecated("Please use `disallowed-names` instead", disallowed_names)]
-    (blacklisted_names: Vec<String> = Vec::new()),
-    /// Lint: COGNITIVE_COMPLEXITY.
-    ///
+    blacklisted_names: Vec<String> = Vec::new(),
+    /// For internal testing only, ignores the current `publish` settings in the Cargo manifest.
+    #[lints(cargo_common_metadata)]
+    cargo_ignore_publish: bool = false,
+    /// Whether to also run the listed lints on private items.
+    #[lints(missing_errors_doc, missing_panics_doc, missing_safety_doc, unnecessary_safety_doc)]
+    check_private_items: bool = false,
     /// The maximum cognitive complexity a function can have
-    (cognitive_complexity_threshold: u64 = 25),
-    /// Lint: EXCESSIVE_NESTING.
-    ///
-    /// The maximum amount of nesting a block can reside in
-    (excessive_nesting_threshold: u64 = 0),
+    #[lints(cognitive_complexity)]
+    cognitive_complexity_threshold: u64 = 25,
     /// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY.
     ///
     /// Use the Cognitive Complexity lint instead.
     #[conf_deprecated("Please use `cognitive-complexity-threshold` instead", cognitive_complexity_threshold)]
-    (cyclomatic_complexity_threshold: u64 = 25),
-    /// Lint: DISALLOWED_NAMES.
-    ///
+    cyclomatic_complexity_threshold: u64 = 25,
+    /// The list of disallowed macros, written as fully qualified paths.
+    #[lints(disallowed_macros)]
+    disallowed_macros: Vec<DisallowedPath> = Vec::new(),
+    /// The list of disallowed methods, written as fully qualified paths.
+    #[lints(disallowed_methods)]
+    disallowed_methods: Vec<DisallowedPath> = Vec::new(),
     /// The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value
     /// `".."` can be used as part of the list to indicate that the configured values should be appended to the
     /// default configuration of Clippy. By default, any configuration will replace the default value.
-    (disallowed_names: Vec<String> = DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()),
-    /// Lint: SEMICOLON_INSIDE_BLOCK.
-    ///
-    /// Whether to lint only if it's multiline.
-    (semicolon_inside_block_ignore_singleline: bool = false),
-    /// Lint: SEMICOLON_OUTSIDE_BLOCK.
-    ///
-    /// Whether to lint only if it's singleline.
-    (semicolon_outside_block_ignore_multiline: bool = false),
-    /// Lint: DOC_MARKDOWN.
-    ///
+    #[lints(disallowed_names)]
+    disallowed_names: Vec<String> = DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect(),
+    /// The list of disallowed types, written as fully qualified paths.
+    #[lints(disallowed_types)]
+    disallowed_types: Vec<DisallowedPath> = Vec::new(),
     /// The list of words this lint should not consider as identifiers needing ticks. The value
     /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the
     /// default configuration of Clippy. By default, any configuration will replace the default value. For example:
     /// * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`.
     /// * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list.
-    (doc_valid_idents: FxHashSet<String> = DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect()),
-    /// Lint: TOO_MANY_ARGUMENTS.
-    ///
-    /// The maximum number of argument a function or method can have
-    (too_many_arguments_threshold: u64 = 7),
-    /// Lint: TYPE_COMPLEXITY.
-    ///
-    /// The maximum complexity a type can have
-    (type_complexity_threshold: u64 = 250),
-    /// Lint: MANY_SINGLE_CHAR_NAMES.
-    ///
-    /// The maximum number of single char bindings a scope may have
-    (single_char_binding_names_threshold: u64 = 4),
-    /// Lint: BOXED_LOCAL, USELESS_VEC.
-    ///
-    /// The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
-    (too_large_for_stack: u64 = 200),
-    /// Lint: ENUM_VARIANT_NAMES.
-    ///
-    /// The minimum number of enum variants for the lints about variant names to trigger
-    (enum_variant_name_threshold: u64 = 3),
-    /// Lint: STRUCT_FIELD_NAMES.
-    ///
-    /// The minimum number of struct fields for the lints about field names to trigger
-    (struct_field_name_threshold: u64 = 3),
-    /// Lint: LARGE_ENUM_VARIANT.
-    ///
-    /// The maximum size of an enum's variant to avoid box suggestion
-    (enum_variant_size_threshold: u64 = 200),
-    /// Lint: VERBOSE_BIT_MASK.
-    ///
-    /// The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros'
-    (verbose_bit_mask_threshold: u64 = 1),
-    /// Lint: DECIMAL_LITERAL_REPRESENTATION.
-    ///
-    /// The lower bound for linting decimal literals
-    (literal_representation_threshold: u64 = 16384),
-    /// Lint: TRIVIALLY_COPY_PASS_BY_REF.
-    ///
-    /// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by
-    /// reference. By default there is no limit
-    #[default_text = ""]
-    (trivial_copy_size_limit: Option<u64> = None),
-    /// Lint: LARGE_TYPES_PASSED_BY_VALUE.
-    ///
-    /// The minimum size (in bytes) to consider a type for passing by reference instead of by value.
-    (pass_by_value_size_limit: u64 = 256),
-    /// Lint: TOO_MANY_LINES.
-    ///
-    /// The maximum number of lines a function or method can have
-    (too_many_lines_threshold: u64 = 100),
-    /// Lint: LARGE_STACK_ARRAYS, LARGE_CONST_ARRAYS.
-    ///
-    /// The maximum allowed size for arrays on the stack
-    (array_size_threshold: u64 = 512_000),
-    /// Lint: LARGE_STACK_FRAMES.
-    ///
-    /// The maximum allowed stack size for functions in bytes
-    (stack_size_threshold: u64 = 512_000),
-    /// Lint: VEC_BOX.
-    ///
-    /// The size of the boxed type in bytes, where boxing in a `Vec` is allowed
-    (vec_box_size_threshold: u64 = 4096),
-    /// Lint: TYPE_REPETITION_IN_BOUNDS.
-    ///
-    /// The maximum number of bounds a trait can have to be linted
-    (max_trait_bounds: u64 = 3),
-    /// Lint: STRUCT_EXCESSIVE_BOOLS.
-    ///
-    /// The maximum number of bool fields a struct can have
-    (max_struct_bools: u64 = 3),
-    /// Lint: FN_PARAMS_EXCESSIVE_BOOLS.
-    ///
-    /// The maximum number of bool parameters a function can have
-    (max_fn_params_bools: u64 = 3),
-    /// Lint: WILDCARD_IMPORTS.
-    ///
-    /// Whether to allow certain wildcard imports (prelude, super in tests).
-    (warn_on_all_wildcard_imports: bool = false),
-    /// Lint: DISALLOWED_MACROS.
-    ///
-    /// The list of disallowed macros, written as fully qualified paths.
-    (disallowed_macros: Vec<DisallowedPath> = Vec::new()),
-    /// Lint: DISALLOWED_METHODS.
-    ///
-    /// The list of disallowed methods, written as fully qualified paths.
-    (disallowed_methods: Vec<DisallowedPath> = Vec::new()),
-    /// Lint: DISALLOWED_TYPES.
-    ///
-    /// The list of disallowed types, written as fully qualified paths.
-    (disallowed_types: Vec<DisallowedPath> = Vec::new()),
-    /// Lint: UNREADABLE_LITERAL.
-    ///
-    /// Should the fraction of a decimal be linted to include separators.
-    (unreadable_literal_lint_fractions: bool = true),
-    /// Lint: UPPER_CASE_ACRONYMS.
-    ///
-    /// Enables verbose mode. Triggers if there is more than one uppercase char next to each other
-    (upper_case_acronyms_aggressive: bool = false),
-    /// Lint: MANUAL_LET_ELSE.
-    ///
-    /// Whether the matches should be considered by the lint, and whether there should
-    /// be filtering for common types.
-    (matches_for_let_else: MatchLintBehaviour = MatchLintBehaviour::WellKnownTypes),
-    /// Lint: CARGO_COMMON_METADATA.
-    ///
-    /// For internal testing only, ignores the current `publish` settings in the Cargo manifest.
-    (cargo_ignore_publish: bool = false),
-    /// Lint: NONSTANDARD_MACRO_BRACES.
-    ///
-    /// Enforce the named macros always use the braces specified.
-    ///
-    /// A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro
-    /// could be used with a full path two `MacroMatcher`s have to be added one with the full path
-    /// `crate_name::macro_name` and one with just the macro name.
-    (standard_macro_braces: Vec<MacroMatcher> = Vec::new()),
-    /// Lint: MISSING_ENFORCED_IMPORT_RENAMES.
-    ///
-    /// The list of imports to always rename, a fully qualified path followed by the rename.
-    (enforced_import_renames: Vec<Rename> = Vec::new()),
-    /// Lint: DISALLOWED_SCRIPT_IDENTS.
-    ///
-    /// The list of unicode scripts allowed to be used in the scope.
-    (allowed_scripts: Vec<String> = vec!["Latin".to_string()]),
-    /// Lint: NON_SEND_FIELDS_IN_SEND_TY.
-    ///
+    #[lints(doc_markdown)]
+    doc_valid_idents: FxHashSet<String> = DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect(),
     /// Whether to apply the raw pointer heuristic to determine if a type is `Send`.
-    (enable_raw_pointer_heuristic_for_send: bool = true),
-    /// Lint: INDEX_REFUTABLE_SLICE.
-    ///
-    /// When Clippy suggests using a slice pattern, this is the maximum number of elements allowed in
-    /// the slice pattern that is suggested. If more elements are necessary, the lint is suppressed.
-    /// For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements.
-    (max_suggested_slice_pattern_length: u64 = 3),
-    /// Lint: AWAIT_HOLDING_INVALID_TYPE.
-    (await_holding_invalid_types: Vec<DisallowedPath> = Vec::new()),
-    /// Lint: LARGE_INCLUDE_FILE.
-    ///
-    /// The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes
-    (max_include_file_size: u64 = 1_000_000),
-    /// Lint: EXPECT_USED.
-    ///
-    /// Whether `expect` should be allowed in test functions or `#[cfg(test)]`
-    (allow_expect_in_tests: bool = false),
-    /// Lint: UNWRAP_USED.
-    ///
-    /// Whether `unwrap` should be allowed in test functions or `#[cfg(test)]`
-    (allow_unwrap_in_tests: bool = false),
-    /// Lint: PANIC.
-    ///
-    /// Whether `panic` should be allowed in test functions or `#[cfg(test)]`
-    (allow_panic_in_tests: bool = false),
-    /// Lint: DBG_MACRO.
-    ///
-    /// Whether `dbg!` should be allowed in test functions or `#[cfg(test)]`
-    (allow_dbg_in_tests: bool = false),
-    /// Lint: PRINT_STDOUT, PRINT_STDERR.
-    ///
-    /// Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]`
-    (allow_print_in_tests: bool = false),
-    /// Lint: USELESS_VEC.
-    ///
-    /// Whether `useless_vec` should ignore test functions or `#[cfg(test)]`
-    (allow_useless_vec_in_tests: bool = false),
-    /// Lint: RESULT_LARGE_ERR.
-    ///
-    /// The maximum size of the `Err`-variant in a `Result` returned from a function
-    (large_error_threshold: u64 = 128),
-    /// Lint: MUTABLE_KEY_TYPE, IFS_SAME_COND, BORROW_INTERIOR_MUTABLE_CONST, DECLARE_INTERIOR_MUTABLE_CONST.
-    ///
-    /// A list of paths to types that should be treated as if they do not contain interior mutability
-    (ignore_interior_mutability: Vec<String> = Vec::from(["bytes::Bytes".into()])),
-    /// Lint: UNINLINED_FORMAT_ARGS.
-    ///
-    /// Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)`
-    (allow_mixed_uninlined_format_args: bool = true),
-    /// Lint: INDEXING_SLICING.
-    ///
-    /// Whether to suppress a restriction lint in constant code. In same
-    /// cases the restructured operation might not be unavoidable, as the
-    /// suggested counterparts are unavailable in constant code. This
-    /// configuration will cause restriction lints to trigger even
-    /// if no suggestion can be made.
-    (suppress_restriction_lint_in_const: bool = false),
-    /// Lint: MISSING_DOCS_IN_PRIVATE_ITEMS.
-    ///
-    /// Whether to **only** check for missing documentation in items visible within the current
-    /// crate. For example, `pub(crate)` items.
-    (missing_docs_in_crate_items: bool = false),
-    /// Lint: LARGE_FUTURES.
-    ///
-    /// The maximum byte size a `Future` can have, before it triggers the `clippy::large_futures` lint
-    (future_size_threshold: u64 = 16 * 1024),
-    /// Lint: UNNECESSARY_BOX_RETURNS.
-    ///
-    /// The byte size a `T` in `Box<T>` can have, below which it triggers the `clippy::unnecessary_box` lint
-    (unnecessary_box_size: u64 = 128),
-    /// Lint: MODULE_INCEPTION.
-    ///
-    /// Whether to allow module inception if it's not public.
-    (allow_private_module_inception: bool = false),
-    /// Lint: MIN_IDENT_CHARS.
-    ///
-    /// Allowed names below the minimum allowed characters. The value `".."` can be used as part of
-    /// the list to indicate, that the configured values should be appended to the default
-    /// configuration of Clippy. By default, any configuration will replace the default value.
-    (allowed_idents_below_min_chars: FxHashSet<String> =
-        DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string).collect()),
-    /// Lint: MIN_IDENT_CHARS.
-    ///
-    /// Minimum chars an ident can have, anything below or equal to this will be linted.
-    (min_ident_chars_threshold: u64 = 1),
-    /// Lint: UNDOCUMENTED_UNSAFE_BLOCKS.
-    ///
-    /// Whether to accept a safety comment to be placed above the statement containing the `unsafe` block
-    (accept_comment_above_statement: bool = true),
-    /// Lint: UNDOCUMENTED_UNSAFE_BLOCKS.
-    ///
-    /// Whether to accept a safety comment to be placed above the attributes for the `unsafe` block
-    (accept_comment_above_attributes: bool = true),
-    /// Lint: UNNECESSARY_RAW_STRING_HASHES.
-    ///
-    /// Whether to allow `r#""#` when `r""` can be used
-    (allow_one_hash_in_raw_strings: bool = false),
-    /// Lint: ABSOLUTE_PATHS.
-    ///
-    /// The maximum number of segments a path can have before being linted, anything above this will
-    /// be linted.
-    (absolute_paths_max_segments: u64 = 2),
-    /// Lint: ABSOLUTE_PATHS.
-    ///
-    /// Which crates to allow absolute paths from
-    (absolute_paths_allowed_crates: FxHashSet<String> = FxHashSet::default()),
-    /// Lint: PATH_ENDS_WITH_EXT.
-    ///
-    /// Additional dotfiles (files or directories starting with a dot) to allow
-    (allowed_dotfiles: Vec<String> = Vec::default()),
-    /// Lint: MULTIPLE_CRATE_VERSIONS.
-    ///
-    /// A list of crate names to allow duplicates of
-    (allowed_duplicate_crates: FxHashSet<String> = FxHashSet::default()),
-    /// Lint: EXPLICIT_ITER_LOOP.
-    ///
+    #[lints(non_send_fields_in_send_ty)]
+    enable_raw_pointer_heuristic_for_send: bool = true,
     /// Whether to recommend using implicit into iter for reborrowed values.
     ///
     /// #### Example
@@ -574,77 +452,195 @@ define_Conf! {
     /// for _ in &*rmvec {}
     /// for _ in &mut *rmvec {}
     /// ```
-    (enforce_iter_loop_reborrow: bool = false),
-    /// Lint: MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC, MISSING_PANICS_DOC, MISSING_ERRORS_DOC.
-    ///
-    /// Whether to also run the listed lints on private items.
-    (check_private_items: bool = false),
-    /// Lint: PUB_UNDERSCORE_FIELDS.
-    ///
+    #[lints(explicit_iter_loop)]
+    enforce_iter_loop_reborrow: bool = false,
+    /// The list of imports to always rename, a fully qualified path followed by the rename.
+    #[lints(missing_enforced_import_renames)]
+    enforced_import_renames: Vec<Rename> = Vec::new(),
+    /// The minimum number of enum variants for the lints about variant names to trigger
+    #[lints(enum_variant_names)]
+    enum_variant_name_threshold: u64 = 3,
+    /// The maximum size of an enum's variant to avoid box suggestion
+    #[lints(large_enum_variant)]
+    enum_variant_size_threshold: u64 = 200,
+    /// The maximum amount of nesting a block can reside in
+    #[lints(excessive_nesting)]
+    excessive_nesting_threshold: u64 = 0,
+    /// The maximum byte size a `Future` can have, before it triggers the `clippy::large_futures` lint
+    #[lints(large_futures)]
+    future_size_threshold: u64 = 16 * 1024,
+    /// A list of paths to types that should be treated as if they do not contain interior mutability
+    #[lints(borrow_interior_mutable_const, declare_interior_mutable_const, ifs_same_cond, mutable_key_type)]
+    ignore_interior_mutability: Vec<String> = Vec::from(["bytes::Bytes".into()]),
+    /// The maximum size of the `Err`-variant in a `Result` returned from a function
+    #[lints(result_large_err)]
+    large_error_threshold: u64 = 128,
+    /// The lower bound for linting decimal literals
+    #[lints(decimal_literal_representation)]
+    literal_representation_threshold: u64 = 16384,
+    /// Whether the matches should be considered by the lint, and whether there should
+    /// be filtering for common types.
+    #[lints(manual_let_else)]
+    matches_for_let_else: MatchLintBehaviour = MatchLintBehaviour::WellKnownTypes,
+    /// The maximum number of bool parameters a function can have
+    #[lints(fn_params_excessive_bools)]
+    max_fn_params_bools: u64 = 3,
+    /// The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes
+    #[lints(large_include_file)]
+    max_include_file_size: u64 = 1_000_000,
+    /// The maximum number of bool fields a struct can have
+    #[lints(struct_excessive_bools)]
+    max_struct_bools: u64 = 3,
+    /// When Clippy suggests using a slice pattern, this is the maximum number of elements allowed in
+    /// the slice pattern that is suggested. If more elements are necessary, the lint is suppressed.
+    /// For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements.
+    #[lints(index_refutable_slice)]
+    max_suggested_slice_pattern_length: u64 = 3,
+    /// The maximum number of bounds a trait can have to be linted
+    #[lints(type_repetition_in_bounds)]
+    max_trait_bounds: u64 = 3,
+    /// Minimum chars an ident can have, anything below or equal to this will be linted.
+    #[lints(min_ident_chars)]
+    min_ident_chars_threshold: u64 = 1,
+    /// Whether to **only** check for missing documentation in items visible within the current
+    /// crate. For example, `pub(crate)` items.
+    #[lints(missing_docs_in_private_items)]
+    missing_docs_in_crate_items: bool = false,
+    /// The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml`
+    #[default_text = "current version"]
+    #[lints(
+        allow_attributes,
+        allow_attributes_without_reason,
+        almost_complete_range,
+        approx_constant,
+        assigning_clones,
+        borrow_as_ptr,
+        cast_abs_to_unsigned,
+        checked_conversions,
+        cloned_instead_of_copied,
+        collapsible_match,
+        collapsible_str_replace,
+        deprecated_cfg_attr,
+        derivable_impls,
+        err_expect,
+        filter_map_next,
+        from_over_into,
+        if_then_some_else_none,
+        index_refutable_slice,
+        iter_kv_map,
+        legacy_numeric_constants,
+        manual_bits,
+        manual_c_str_literals,
+        manual_clamp,
+        manual_hash_one,
+        manual_is_ascii_check,
+        manual_let_else,
+        manual_non_exhaustive,
+        manual_pattern_char_comparison,
+        manual_range_contains,
+        manual_rem_euclid,
+        manual_retain,
+        manual_split_once,
+        manual_str_repeat,
+        manual_strip,
+        manual_try_fold,
+        map_clone,
+        map_unwrap_or,
+        match_like_matches_macro,
+        mem_replace_with_default,
+        missing_const_for_fn,
+        needless_borrow,
+        option_as_ref_deref,
+        option_map_unwrap_or,
+        ptr_as_ptr,
+        redundant_field_names,
+        redundant_static_lifetimes,
+        seek_from_current,
+        seek_rewind,
+        transmute_ptr_to_ref,
+        tuple_array_conversions,
+        type_repetition_in_bounds,
+        unchecked_duration_subtraction,
+        uninlined_format_args,
+        unnecessary_lazy_evaluations,
+        unnested_or_patterns,
+        use_self,
+    )]
+    msrv: Msrv = Msrv::empty(),
+    /// The minimum size (in bytes) to consider a type for passing by reference instead of by value.
+    #[lints(large_types_passed_by_value)]
+    pass_by_value_size_limit: u64 = 256,
     /// Lint "public" fields in a struct that are prefixed with an underscore based on their
     /// exported visibility, or whether they are marked as "pub".
-    (pub_underscore_fields_behavior: PubUnderscoreFieldsBehaviour = PubUnderscoreFieldsBehaviour::PubliclyExported),
-    /// Lint: MODULO_ARITHMETIC.
-    ///
-    /// Don't lint when comparing the result of a modulo operation to zero.
-    (allow_comparison_to_zero: bool = true),
-    /// Lint: WILDCARD_IMPORTS.
-    ///
-    /// List of path segments allowed to have wildcard imports.
-    ///
-    /// #### Example
-    ///
-    /// ```toml
-    /// allowed-wildcard-imports = [ "utils", "common" ]
-    /// ```
-    ///
-    /// #### Noteworthy
-    ///
-    /// 1. This configuration has no effects if used with `warn_on_all_wildcard_imports = true`.
-    /// 2. Paths with any segment that containing the word 'prelude'
-    /// are already allowed by default.
-    (allowed_wildcard_imports: FxHashSet<String> = FxHashSet::default()),
-    /// Lint: MODULE_NAME_REPETITIONS.
-    ///
-    /// List of prefixes to allow when determining whether an item's name ends with the module's name.
-    /// If the rest of an item's name is an allowed prefix (e.g. item `ToFoo` or `to_foo` in module `foo`),
-    /// then don't emit a warning.
-    ///
-    /// #### Example
-    ///
-    /// ```toml
-    /// allowed-prefixes = [ "to", "from" ]
-    /// ```
-    ///
-    /// #### Noteworthy
-    ///
-    /// - By default, the following prefixes are allowed: `to`, `as`, `into`, `from`, `try_into` and `try_from`
-    /// - PascalCase variant is included automatically for each snake_case variant (e.g. if `try_into` is included,
-    ///   `TryInto` will also be included)
-    /// - Use `".."` as part of the list to indicate that the configured values should be appended to the
-    /// default configuration of Clippy. By default, any configuration will replace the default value
-    (allowed_prefixes: Vec<String> = DEFAULT_ALLOWED_PREFIXES.iter().map(ToString::to_string).collect()),
-    /// Lint: RENAMED_FUNCTION_PARAMS.
-    ///
-    /// List of trait paths to ignore when checking renamed function parameters.
-    ///
-    /// #### Example
-    ///
-    /// ```toml
-    /// allow-renamed-params-for = [ "std::convert::From" ]
-    /// ```
-    ///
-    /// #### Noteworthy
-    ///
-    /// - By default, the following traits are ignored: `From`, `TryFrom`, `FromStr`
-    /// - `".."` can be used as part of the list to indicate that the configured values should be appended to the
-    /// default configuration of Clippy. By default, any configuration will replace the default value.
-    (allow_renamed_params_for: Vec<String> =
-        DEFAULT_ALLOWED_TRAITS_WITH_RENAMED_PARAMS.iter().map(ToString::to_string).collect()),
-    /// Lint: MACRO_METAVARS_IN_UNSAFE.
+    #[lints(pub_underscore_fields)]
+    pub_underscore_fields_behavior: PubUnderscoreFieldsBehaviour = PubUnderscoreFieldsBehaviour::PubliclyExported,
+    /// Whether to lint only if it's multiline.
+    #[lints(semicolon_inside_block)]
+    semicolon_inside_block_ignore_singleline: bool = false,
+    /// Whether to lint only if it's singleline.
+    #[lints(semicolon_outside_block)]
+    semicolon_outside_block_ignore_multiline: bool = false,
+    /// The maximum number of single char bindings a scope may have
+    #[lints(many_single_char_names)]
+    single_char_binding_names_threshold: u64 = 4,
+    /// The maximum allowed stack size for functions in bytes
+    #[lints(large_stack_frames)]
+    stack_size_threshold: u64 = 512_000,
+    /// Enforce the named macros always use the braces specified.
     ///
+    /// A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro
+    /// could be used with a full path two `MacroMatcher`s have to be added one with the full path
+    /// `crate_name::macro_name` and one with just the macro name.
+    #[lints(nonstandard_macro_braces)]
+    standard_macro_braces: Vec<MacroMatcher> = Vec::new(),
+    /// The minimum number of struct fields for the lints about field names to trigger
+    #[lints(struct_field_names)]
+    struct_field_name_threshold: u64 = 3,
+    /// Whether to suppress a restriction lint in constant code. In same
+    /// cases the restructured operation might not be unavoidable, as the
+    /// suggested counterparts are unavailable in constant code. This
+    /// configuration will cause restriction lints to trigger even
+    /// if no suggestion can be made.
+    #[lints(indexing_slicing)]
+    suppress_restriction_lint_in_const: bool = false,
+    /// The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
+    #[lints(boxed_local, useless_vec)]
+    too_large_for_stack: u64 = 200,
+    /// The maximum number of argument a function or method can have
+    #[lints(too_many_arguments)]
+    too_many_arguments_threshold: u64 = 7,
+    /// The maximum number of lines a function or method can have
+    #[lints(too_many_lines)]
+    too_many_lines_threshold: u64 = 100,
+    /// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by
+    /// reference. By default there is no limit
+    #[default_text = "target_pointer_width * 2"]
+    #[lints(trivially_copy_pass_by_ref)]
+    trivial_copy_size_limit: Option<u64> = None,
+    /// The maximum complexity a type can have
+    #[lints(type_complexity)]
+    type_complexity_threshold: u64 = 250,
+    /// The byte size a `T` in `Box<T>` can have, below which it triggers the `clippy::unnecessary_box` lint
+    #[lints(unnecessary_box_returns)]
+    unnecessary_box_size: u64 = 128,
+    /// Should the fraction of a decimal be linted to include separators.
+    #[lints(unreadable_literal)]
+    unreadable_literal_lint_fractions: bool = true,
+    /// Enables verbose mode. Triggers if there is more than one uppercase char next to each other
+    #[lints(upper_case_acronyms)]
+    upper_case_acronyms_aggressive: bool = false,
+    /// The size of the boxed type in bytes, where boxing in a `Vec` is allowed
+    #[lints(vec_box)]
+    vec_box_size_threshold: u64 = 4096,
+    /// The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros'
+    #[lints(verbose_bit_mask)]
+    verbose_bit_mask_threshold: u64 = 1,
+    /// Whether to allow certain wildcard imports (prelude, super in tests).
+    #[lints(wildcard_imports)]
+    warn_on_all_wildcard_imports: bool = false,
     /// Whether to also emit warnings for unsafe blocks with metavariable expansions in **private** macros.
-    (warn_unsafe_macro_metavars_in_private_macros: bool = false),
+    #[lints(macro_metavars_in_unsafe)]
+    warn_unsafe_macro_metavars_in_private_macros: bool = false,
 }
 
 /// Search for the configuration file.
diff --git a/src/tools/clippy/clippy_config/src/lib.rs b/src/tools/clippy/clippy_config/src/lib.rs
index ff7fa7241cb..d2246f12029 100644
--- a/src/tools/clippy/clippy_config/src/lib.rs
+++ b/src/tools/clippy/clippy_config/src/lib.rs
@@ -1,5 +1,4 @@
-#![feature(rustc_private, let_chains)]
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
+#![feature(rustc_private, array_windows, let_chains)]
 #![warn(
     trivial_casts,
     trivial_numeric_casts,
diff --git a/src/tools/clippy/clippy_config/src/metadata.rs b/src/tools/clippy/clippy_config/src/metadata.rs
index 400887185e8..7cbd92a9b71 100644
--- a/src/tools/clippy/clippy_config/src/metadata.rs
+++ b/src/tools/clippy/clippy_config/src/metadata.rs
@@ -1,11 +1,12 @@
-use std::fmt::{self, Write};
+use itertools::Itertools;
+use std::fmt;
 
 #[derive(Debug, Clone, Default)]
 pub struct ClippyConfiguration {
     pub name: String,
     pub default: String,
-    pub lints: Vec<String>,
-    pub doc: String,
+    pub lints: &'static [&'static str],
+    pub doc: &'static str,
     pub deprecation_reason: Option<&'static str>,
 }
 
@@ -13,61 +14,23 @@ impl fmt::Display for ClippyConfiguration {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "- `{}`: {}", self.name, self.doc)?;
         if !self.default.is_empty() {
-            write!(f, " (default: `{}`)", self.default)?;
+            write!(f, "\n\n   (default: `{}`)", self.default)?;
         }
         Ok(())
     }
 }
 
 impl ClippyConfiguration {
-    pub fn new(
-        name: &'static str,
-        default: String,
-        doc_comment: &'static str,
-        deprecation_reason: Option<&'static str>,
-    ) -> Self {
-        let (mut lints, doc) = parse_config_field_doc(doc_comment)
-            .unwrap_or_else(|| (vec![], "[ERROR] MALFORMED DOC COMMENT".to_string()));
-
-        lints.sort();
-
-        Self {
-            name: to_kebab(name),
-            lints,
-            doc,
-            default,
-            deprecation_reason,
-        }
-    }
-
     pub fn to_markdown_paragraph(&self) -> String {
-        let mut out = format!(
-            "## `{}`\n{}\n\n",
+        format!(
+            "## `{}`\n{}\n\n**Default Value:** `{}`\n\n---\n**Affected lints:**\n{}\n\n",
             self.name,
-            self.doc
-                .lines()
-                .map(|line| line.strip_prefix("    ").unwrap_or(line))
-                .collect::<Vec<_>>()
-                .join("\n"),
-        );
-
-        if !self.default.is_empty() {
-            write!(out, "**Default Value:** `{}`\n\n", self.default).unwrap();
-        }
-
-        write!(
-            out,
-            "---\n**Affected lints:**\n{}\n\n",
-            self.lints
-                .iter()
-                .map(|name| name.to_string().split_whitespace().next().unwrap().to_string())
-                .map(|name| format!("* [`{name}`](https://rust-lang.github.io/rust-clippy/master/index.html#{name})"))
-                .collect::<Vec<_>>()
-                .join("\n"),
+            self.doc.lines().map(|x| x.strip_prefix(' ').unwrap_or(x)).join("\n"),
+            self.default,
+            self.lints.iter().format_with("\n", |name, f| f(&format_args!(
+                "* [`{name}`](https://rust-lang.github.io/rust-clippy/master/index.html#{name})"
+            ))),
         )
-        .unwrap();
-
-        out
     }
 
     pub fn to_markdown_link(&self) -> String {
@@ -75,47 +38,3 @@ impl ClippyConfiguration {
         format!("[`{}`]: {BOOK_CONFIGS_PATH}#{}", self.name, self.name)
     }
 }
-
-/// This parses the field documentation of the config struct.
-///
-/// ```rust, ignore
-/// parse_config_field_doc(cx, "Lint: LINT_NAME_1, LINT_NAME_2. Papa penguin, papa penguin")
-/// ```
-///
-/// Would yield:
-/// ```rust, ignore
-/// Some(["lint_name_1", "lint_name_2"], "Papa penguin, papa penguin")
-/// ```
-fn parse_config_field_doc(doc_comment: &str) -> Option<(Vec<String>, String)> {
-    const DOC_START: &str = " Lint: ";
-    if doc_comment.starts_with(DOC_START)
-        && let Some(split_pos) = doc_comment.find('.')
-    {
-        let mut doc_comment = doc_comment.to_string();
-        let mut documentation = doc_comment.split_off(split_pos);
-
-        // Extract lints
-        doc_comment.make_ascii_lowercase();
-        let lints: Vec<String> = doc_comment
-            .split_off(DOC_START.len())
-            .lines()
-            .next()
-            .unwrap()
-            .split(", ")
-            .map(str::to_string)
-            .collect();
-
-        // Format documentation correctly
-        // split off leading `.` from lint name list and indent for correct formatting
-        documentation = documentation.trim_start_matches('.').trim().replace("\n ", "\n    ");
-
-        Some((lints, documentation))
-    } else {
-        None
-    }
-}
-
-/// Transforms a given `snake_case_string` to a tasty `kebab-case-string`
-fn to_kebab(config_name: &str) -> String {
-    config_name.replace('_', "-")
-}
diff --git a/src/tools/clippy/clippy_dev/Cargo.toml b/src/tools/clippy/clippy_dev/Cargo.toml
index 4104e7d94f1..a5d72c3a559 100644
--- a/src/tools/clippy/clippy_dev/Cargo.toml
+++ b/src/tools/clippy/clippy_dev/Cargo.toml
@@ -13,9 +13,6 @@ opener = "0.6"
 shell-escape = "0.1"
 walkdir = "2.3"
 
-[features]
-deny-warnings = []
-
 [package.metadata.rust-analyzer]
 # This package uses #[feature(rustc_private)]
 rustc_private = true
diff --git a/src/tools/clippy/clippy_dev/src/fmt.rs b/src/tools/clippy/clippy_dev/src/fmt.rs
index 25623144181..5fc4365c6e7 100644
--- a/src/tools/clippy/clippy_dev/src/fmt.rs
+++ b/src/tools/clippy/clippy_dev/src/fmt.rs
@@ -1,30 +1,65 @@
 use crate::clippy_project_root;
 use itertools::Itertools;
+use rustc_lexer::{tokenize, TokenKind};
 use shell_escape::escape;
 use std::ffi::{OsStr, OsString};
-use std::path::Path;
+use std::ops::ControlFlow;
+use std::path::{Path, PathBuf};
 use std::process::{self, Command, Stdio};
 use std::{fs, io};
 use walkdir::WalkDir;
 
-#[derive(Debug)]
-pub enum CliError {
+pub enum Error {
     CommandFailed(String, String),
-    IoError(io::Error),
+    Io(io::Error),
     RustfmtNotInstalled,
-    WalkDirError(walkdir::Error),
+    WalkDir(walkdir::Error),
     IntellijSetupActive,
+    Parse(PathBuf, usize, String),
+    CheckFailed,
 }
 
-impl From<io::Error> for CliError {
+impl From<io::Error> for Error {
     fn from(error: io::Error) -> Self {
-        Self::IoError(error)
+        Self::Io(error)
     }
 }
 
-impl From<walkdir::Error> for CliError {
+impl From<walkdir::Error> for Error {
     fn from(error: walkdir::Error) -> Self {
-        Self::WalkDirError(error)
+        Self::WalkDir(error)
+    }
+}
+
+impl Error {
+    fn display(&self) {
+        match self {
+            Self::CheckFailed => {
+                eprintln!("Formatting check failed!\nRun `cargo dev fmt` to update.");
+            },
+            Self::CommandFailed(command, stderr) => {
+                eprintln!("error: command `{command}` failed!\nstderr: {stderr}");
+            },
+            Self::Io(err) => {
+                eprintln!("error: {err}");
+            },
+            Self::RustfmtNotInstalled => {
+                eprintln!("error: rustfmt nightly is not installed.");
+            },
+            Self::WalkDir(err) => {
+                eprintln!("error: {err}");
+            },
+            Self::IntellijSetupActive => {
+                eprintln!(
+                    "error: a local rustc repo is enabled as path dependency via `cargo dev setup intellij`.\n\
+                    Not formatting because that would format the local repo as well!\n\
+                    Please revert the changes to `Cargo.toml`s with `cargo dev remove intellij`."
+                );
+            },
+            Self::Parse(path, line, msg) => {
+                eprintln!("error parsing `{}:{line}`: {msg}", path.display());
+            },
+        }
     }
 }
 
@@ -34,75 +69,244 @@ struct FmtContext {
     rustfmt_path: String,
 }
 
-// the "main" function of cargo dev fmt
-pub fn run(check: bool, verbose: bool) {
-    fn try_run(context: &FmtContext) -> Result<bool, CliError> {
-        let mut success = true;
-
-        let project_root = clippy_project_root();
-
-        // if we added a local rustc repo as path dependency to clippy for rust analyzer, we do NOT want to
-        // format because rustfmt would also format the entire rustc repo as it is a local
-        // dependency
-        if fs::read_to_string(project_root.join("Cargo.toml"))
-            .expect("Failed to read clippy Cargo.toml")
-            .contains("[target.'cfg(NOT_A_PLATFORM)'.dependencies]")
-        {
-            return Err(CliError::IntellijSetupActive);
-        }
-
-        rustfmt_test(context)?;
+struct ClippyConf<'a> {
+    name: &'a str,
+    attrs: &'a str,
+    lints: Vec<&'a str>,
+    field: &'a str,
+}
 
-        success &= cargo_fmt(context, project_root.as_path())?;
-        success &= cargo_fmt(context, &project_root.join("clippy_dev"))?;
-        success &= cargo_fmt(context, &project_root.join("rustc_tools_util"))?;
-        success &= cargo_fmt(context, &project_root.join("lintcheck"))?;
+fn offset_to_line(text: &str, offset: usize) -> usize {
+    match text.split('\n').try_fold((1usize, 0usize), |(line, pos), s| {
+        let pos = pos + s.len() + 1;
+        if pos > offset {
+            ControlFlow::Break(line)
+        } else {
+            ControlFlow::Continue((line + 1, pos))
+        }
+    }) {
+        ControlFlow::Break(x) | ControlFlow::Continue((x, _)) => x,
+    }
+}
 
-        let chunks = WalkDir::new(project_root.join("tests"))
-            .into_iter()
-            .filter_map(|entry| {
-                let entry = entry.expect("failed to find tests");
-                let path = entry.path();
+/// Formats the configuration list in `clippy_config/src/conf.rs`
+#[expect(clippy::too_many_lines)]
+fn fmt_conf(check: bool) -> Result<(), Error> {
+    #[derive(Clone, Copy)]
+    enum State {
+        Start,
+        Docs,
+        Pound,
+        OpenBracket,
+        Attr(u32),
+        Lints,
+        EndLints,
+        Field,
+    }
 
-                if path.extension() != Some("rs".as_ref()) || entry.file_name() == "ice-3891.rs" {
-                    None
-                } else {
-                    Some(entry.into_path().into_os_string())
-                }
-            })
-            .chunks(250);
+    let path: PathBuf = [
+        clippy_project_root().as_path(),
+        "clippy_config".as_ref(),
+        "src".as_ref(),
+        "conf.rs".as_ref(),
+    ]
+    .into_iter()
+    .collect();
+    let text = fs::read_to_string(&path)?;
 
-        for chunk in &chunks {
-            success &= rustfmt(context, chunk)?;
-        }
+    let (pre, conf) = text
+        .split_once("define_Conf! {\n")
+        .expect("can't find config definition");
+    let (conf, post) = conf.split_once("\n}\n").expect("can't find config definition");
+    let conf_offset = pre.len() + 15;
 
-        Ok(success)
-    }
+    let mut pos = 0u32;
+    let mut attrs_start = 0;
+    let mut attrs_end = 0;
+    let mut field_start = 0;
+    let mut lints = Vec::new();
+    let mut name = "";
+    let mut fields = Vec::new();
+    let mut state = State::Start;
 
-    fn output_err(err: CliError) {
-        match err {
-            CliError::CommandFailed(command, stderr) => {
-                eprintln!("error: A command failed! `{command}`\nstderr: {stderr}");
+    for (i, t) in tokenize(conf)
+        .map(|x| {
+            let start = pos;
+            pos += x.len;
+            (start as usize, x)
+        })
+        .filter(|(_, t)| !matches!(t.kind, TokenKind::Whitespace))
+    {
+        match (state, t.kind) {
+            (State::Start, TokenKind::LineComment { doc_style: Some(_) }) => {
+                attrs_start = i;
+                attrs_end = i + t.len as usize;
+                state = State::Docs;
             },
-            CliError::IoError(err) => {
-                eprintln!("error: {err}");
+            (State::Start, TokenKind::Pound) => {
+                attrs_start = i;
+                attrs_end = i;
+                state = State::Pound;
             },
-            CliError::RustfmtNotInstalled => {
-                eprintln!("error: rustfmt nightly is not installed.");
+            (State::Docs, TokenKind::LineComment { doc_style: Some(_) }) => attrs_end = i + t.len as usize,
+            (State::Docs, TokenKind::Pound) => state = State::Pound,
+            (State::Pound, TokenKind::OpenBracket) => state = State::OpenBracket,
+            (State::OpenBracket, TokenKind::Ident) => {
+                state = if conf[i..i + t.len as usize] == *"lints" {
+                    State::Lints
+                } else {
+                    State::Attr(0)
+                };
             },
-            CliError::WalkDirError(err) => {
-                eprintln!("error: {err}");
+            (State::Attr(0), TokenKind::CloseBracket) => {
+                attrs_end = i + 1;
+                state = State::Docs;
             },
-            CliError::IntellijSetupActive => {
-                eprintln!(
-                    "error: a local rustc repo is enabled as path dependency via `cargo dev setup intellij`.
-Not formatting because that would format the local repo as well!
-Please revert the changes to Cargo.tomls with `cargo dev remove intellij`."
-                );
+            (State::Attr(x), TokenKind::OpenParen | TokenKind::OpenBracket | TokenKind::OpenBrace) => {
+                state = State::Attr(x + 1);
+            },
+            (State::Attr(x), TokenKind::CloseParen | TokenKind::CloseBracket | TokenKind::CloseBrace) => {
+                state = State::Attr(x - 1);
+            },
+            (State::Lints, TokenKind::Ident) => lints.push(&conf[i..i + t.len as usize]),
+            (State::Lints, TokenKind::CloseBracket) => state = State::EndLints,
+            (State::EndLints | State::Docs, TokenKind::Ident) => {
+                field_start = i;
+                name = &conf[i..i + t.len as usize];
+                state = State::Field;
+            },
+            (State::Field, TokenKind::LineComment { doc_style: Some(_) }) => {
+                #[expect(clippy::drain_collect)]
+                fields.push(ClippyConf {
+                    name,
+                    lints: lints.drain(..).collect(),
+                    attrs: &conf[attrs_start..attrs_end],
+                    field: conf[field_start..i].trim_end(),
+                });
+                attrs_start = i;
+                attrs_end = i + t.len as usize;
+                state = State::Docs;
+            },
+            (State::Field, TokenKind::Pound) => {
+                #[expect(clippy::drain_collect)]
+                fields.push(ClippyConf {
+                    name,
+                    lints: lints.drain(..).collect(),
+                    attrs: &conf[attrs_start..attrs_end],
+                    field: conf[field_start..i].trim_end(),
+                });
+                attrs_start = i;
+                attrs_end = i;
+                state = State::Pound;
+            },
+            (State::Field | State::Attr(_), _)
+            | (State::Lints, TokenKind::Comma | TokenKind::OpenParen | TokenKind::CloseParen) => {},
+            _ => {
+                return Err(Error::Parse(
+                    path,
+                    offset_to_line(&text, conf_offset + i),
+                    format!("unexpected token `{}`", &conf[i..i + t.len as usize]),
+                ));
             },
         }
     }
 
+    if !matches!(state, State::Field) {
+        return Err(Error::Parse(
+            path,
+            offset_to_line(&text, conf_offset + conf.len()),
+            "incomplete field".into(),
+        ));
+    }
+    fields.push(ClippyConf {
+        name,
+        lints,
+        attrs: &conf[attrs_start..attrs_end],
+        field: conf[field_start..].trim_end(),
+    });
+
+    for field in &mut fields {
+        field.lints.sort_unstable();
+    }
+    fields.sort_by_key(|x| x.name);
+
+    let new_text = format!(
+        "{pre}define_Conf! {{\n{}}}\n{post}",
+        fields.iter().format_with("", |field, f| {
+            if field.lints.is_empty() {
+                f(&format_args!("    {}\n    {}\n", field.attrs, field.field))
+            } else if field.lints.iter().map(|x| x.len() + 2).sum::<usize>() < 120 - 14 {
+                f(&format_args!(
+                    "    {}\n    #[lints({})]\n    {}\n",
+                    field.attrs,
+                    field.lints.iter().join(", "),
+                    field.field,
+                ))
+            } else {
+                f(&format_args!(
+                    "    {}\n    #[lints({}\n    )]\n    {}\n",
+                    field.attrs,
+                    field
+                        .lints
+                        .iter()
+                        .format_with("", |x, f| f(&format_args!("\n        {x},"))),
+                    field.field,
+                ))
+            }
+        })
+    );
+
+    if text != new_text {
+        if check {
+            return Err(Error::CheckFailed);
+        }
+        fs::write(&path, new_text.as_bytes())?;
+    }
+    Ok(())
+}
+
+fn run_rustfmt(context: &FmtContext) -> Result<(), Error> {
+    let project_root = clippy_project_root();
+
+    // if we added a local rustc repo as path dependency to clippy for rust analyzer, we do NOT want to
+    // format because rustfmt would also format the entire rustc repo as it is a local
+    // dependency
+    if fs::read_to_string(project_root.join("Cargo.toml"))
+        .expect("Failed to read clippy Cargo.toml")
+        .contains("[target.'cfg(NOT_A_PLATFORM)'.dependencies]")
+    {
+        return Err(Error::IntellijSetupActive);
+    }
+
+    check_for_rustfmt(context)?;
+
+    cargo_fmt(context, project_root.as_path())?;
+    cargo_fmt(context, &project_root.join("clippy_dev"))?;
+    cargo_fmt(context, &project_root.join("rustc_tools_util"))?;
+    cargo_fmt(context, &project_root.join("lintcheck"))?;
+
+    let chunks = WalkDir::new(project_root.join("tests"))
+        .into_iter()
+        .filter_map(|entry| {
+            let entry = entry.expect("failed to find tests");
+            let path = entry.path();
+
+            if path.extension() != Some("rs".as_ref()) || entry.file_name() == "ice-3891.rs" {
+                None
+            } else {
+                Some(entry.into_path().into_os_string())
+            }
+        })
+        .chunks(250);
+
+    for chunk in &chunks {
+        rustfmt(context, chunk)?;
+    }
+    Ok(())
+}
+
+// the "main" function of cargo dev fmt
+pub fn run(check: bool, verbose: bool) {
     let output = Command::new("rustup")
         .args(["which", "rustfmt"])
         .stderr(Stdio::inherit())
@@ -120,21 +324,10 @@ Please revert the changes to Cargo.tomls with `cargo dev remove intellij`."
         verbose,
         rustfmt_path,
     };
-    let result = try_run(&context);
-    let code = match result {
-        Ok(true) => 0,
-        Ok(false) => {
-            eprintln!();
-            eprintln!("Formatting check failed.");
-            eprintln!("Run `cargo dev fmt` to update formatting.");
-            1
-        },
-        Err(err) => {
-            output_err(err);
-            1
-        },
-    };
-    process::exit(code);
+    if let Err(e) = run_rustfmt(&context).and_then(|()| fmt_conf(check)) {
+        e.display();
+        process::exit(1);
+    }
 }
 
 fn format_command(program: impl AsRef<OsStr>, dir: impl AsRef<Path>, args: &[impl AsRef<OsStr>]) -> String {
@@ -148,12 +341,12 @@ fn format_command(program: impl AsRef<OsStr>, dir: impl AsRef<Path>, args: &[imp
     )
 }
 
-fn exec(
+fn exec_fmt_command(
     context: &FmtContext,
     program: impl AsRef<OsStr>,
     dir: impl AsRef<Path>,
     args: &[impl AsRef<OsStr>],
-) -> Result<bool, CliError> {
+) -> Result<(), Error> {
     if context.verbose {
         println!("{}", format_command(&program, &dir, args));
     }
@@ -166,28 +359,28 @@ fn exec(
         .unwrap();
     let success = output.status.success();
 
-    if !context.check && !success {
-        let stderr = std::str::from_utf8(&output.stderr).unwrap_or("");
-        return Err(CliError::CommandFailed(
-            format_command(&program, &dir, args),
-            String::from(stderr),
-        ));
+    match (context.check, success) {
+        (_, true) => Ok(()),
+        (true, false) => Err(Error::CheckFailed),
+        (false, false) => {
+            let stderr = std::str::from_utf8(&output.stderr).unwrap_or("");
+            Err(Error::CommandFailed(
+                format_command(&program, &dir, args),
+                String::from(stderr),
+            ))
+        },
     }
-
-    Ok(success)
 }
 
-fn cargo_fmt(context: &FmtContext, path: &Path) -> Result<bool, CliError> {
+fn cargo_fmt(context: &FmtContext, path: &Path) -> Result<(), Error> {
     let mut args = vec!["fmt", "--all"];
     if context.check {
         args.push("--check");
     }
-    let success = exec(context, "cargo", path, &args)?;
-
-    Ok(success)
+    exec_fmt_command(context, "cargo", path, &args)
 }
 
-fn rustfmt_test(context: &FmtContext) -> Result<(), CliError> {
+fn check_for_rustfmt(context: &FmtContext) -> Result<(), Error> {
     let program = "rustfmt";
     let dir = std::env::current_dir()?;
     let args = &["--version"];
@@ -204,23 +397,20 @@ fn rustfmt_test(context: &FmtContext) -> Result<(), CliError> {
         .unwrap_or("")
         .starts_with("error: 'rustfmt' is not installed")
     {
-        Err(CliError::RustfmtNotInstalled)
+        Err(Error::RustfmtNotInstalled)
     } else {
-        Err(CliError::CommandFailed(
+        Err(Error::CommandFailed(
             format_command(program, &dir, args),
             std::str::from_utf8(&output.stderr).unwrap_or("").to_string(),
         ))
     }
 }
 
-fn rustfmt(context: &FmtContext, paths: impl Iterator<Item = OsString>) -> Result<bool, CliError> {
+fn rustfmt(context: &FmtContext, paths: impl Iterator<Item = OsString>) -> Result<(), Error> {
     let mut args = Vec::new();
     if context.check {
         args.push(OsString::from("--check"));
     }
     args.extend(paths);
-
-    let success = exec(context, &context.rustfmt_path, std::env::current_dir()?, &args)?;
-
-    Ok(success)
+    exec_fmt_command(context, &context.rustfmt_path, std::env::current_dir()?, &args)
 }
diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs
index 3aa43dbe23e..ad385d5fbd2 100644
--- a/src/tools/clippy/clippy_dev/src/lib.rs
+++ b/src/tools/clippy/clippy_dev/src/lib.rs
@@ -1,6 +1,5 @@
 #![feature(let_chains)]
 #![feature(rustc_private)]
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![warn(
     trivial_casts,
     trivial_numeric_casts,
diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs
index 366b52b25df..755b04b0b23 100644
--- a/src/tools/clippy/clippy_dev/src/main.rs
+++ b/src/tools/clippy/clippy_dev/src/main.rs
@@ -1,4 +1,3 @@
-#![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)]
 
@@ -74,7 +73,7 @@ fn main() {
             new_name,
             uplift,
         } => update_lints::rename(&old_name, new_name.as_ref().unwrap_or(&old_name), uplift),
-        DevCommand::Deprecate { name, reason } => update_lints::deprecate(&name, reason.as_deref()),
+        DevCommand::Deprecate { name, reason } => update_lints::deprecate(&name, &reason),
     }
 }
 
@@ -223,7 +222,7 @@ enum DevCommand {
         name: String,
         #[arg(long, short)]
         /// The reason for deprecation
-        reason: Option<String>,
+        reason: String,
     },
 }
 
diff --git a/src/tools/clippy/clippy_dev/src/serve.rs b/src/tools/clippy/clippy_dev/src/serve.rs
index 4a4261d1a1e..19560b31fd3 100644
--- a/src/tools/clippy/clippy_dev/src/serve.rs
+++ b/src/tools/clippy/clippy_dev/src/serve.rs
@@ -1,10 +1,14 @@
-use std::ffi::OsStr;
-use std::num::ParseIntError;
 use std::path::Path;
 use std::process::Command;
 use std::time::{Duration, SystemTime};
 use std::{env, thread};
 
+#[cfg(windows)]
+const PYTHON: &str = "python";
+
+#[cfg(not(windows))]
+const PYTHON: &str = "python3";
+
 /// # Panics
 ///
 /// Panics if the python commands could not be spawned
@@ -25,7 +29,7 @@ pub fn run(port: u16, lint: Option<String>) -> ! {
         }
         if let Some(url) = url.take() {
             thread::spawn(move || {
-                Command::new("python3")
+                Command::new(PYTHON)
                     .arg("-m")
                     .arg("http.server")
                     .arg(port.to_string())
@@ -58,8 +62,3 @@ fn mtime(path: impl AsRef<Path>) -> SystemTime {
             .unwrap_or(SystemTime::UNIX_EPOCH)
     }
 }
-
-#[allow(clippy::missing_errors_doc)]
-pub fn validate_port(arg: &OsStr) -> Result<(), ParseIntError> {
-    arg.to_string_lossy().parse::<u16>().map(|_| ())
-}
diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs
index 45353901c98..15578d69c3a 100644
--- a/src/tools/clippy/clippy_dev/src/update_lints.rs
+++ b/src/tools/clippy/clippy_dev/src/update_lints.rs
@@ -1,13 +1,12 @@
 use crate::clippy_project_root;
 use aho_corasick::AhoCorasickBuilder;
-use indoc::writedoc;
 use itertools::Itertools;
 use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind};
 use std::collections::{HashMap, HashSet};
 use std::ffi::OsStr;
 use std::fmt::{self, Write};
 use std::fs::{self, OpenOptions};
-use std::io::{self, Read, Seek, SeekFrom, Write as _};
+use std::io::{self, Read, Seek, Write as _};
 use std::ops::Range;
 use std::path::{Path, PathBuf};
 use walkdir::{DirEntry, WalkDir};
@@ -77,12 +76,8 @@ fn generate_lint_files(
             for lint in usable_lints
                 .iter()
                 .map(|l| &*l.name)
-                .chain(deprecated_lints.iter().map(|l| &*l.name))
-                .chain(
-                    renamed_lints
-                        .iter()
-                        .map(|l| l.old_name.strip_prefix("clippy::").unwrap_or(&l.old_name)),
-                )
+                .chain(deprecated_lints.iter().filter_map(|l| l.name.strip_prefix("clippy::")))
+                .chain(renamed_lints.iter().filter_map(|l| l.old_name.strip_prefix("clippy::")))
                 .sorted()
             {
                 writeln!(res, "[`{lint}`]: {DOCS_LINK}#{lint}").unwrap();
@@ -108,11 +103,6 @@ fn generate_lint_files(
         update_mode,
         &gen_declared_lints(internal_lints.iter(), usable_lints.iter()),
     );
-    process_file(
-        "clippy_lints/src/lib.deprecated.rs",
-        update_mode,
-        &gen_deprecated(deprecated_lints),
-    );
 
     let content = gen_deprecated_lints_test(deprecated_lints);
     process_file("tests/ui/deprecated.rs", update_mode, &content);
@@ -205,7 +195,7 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) {
             let ext = f.path().extension();
             (ext == Some(OsStr::new("rs")) || ext == Some(OsStr::new("fixed")))
                 && name != Some(OsStr::new("rename.rs"))
-                && name != Some(OsStr::new("renamed_lints.rs"))
+                && name != Some(OsStr::new("deprecated_lints.rs"))
         })
     {
         rewrite_file(file.path(), |s| {
@@ -213,6 +203,19 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) {
         });
     }
 
+    let version = crate::new_lint::get_stabilization_version();
+    rewrite_file(Path::new("clippy_lints/src/deprecated_lints.rs"), |s| {
+        insert_at_marker(
+            s,
+            "// end renamed lints. used by `cargo dev rename_lint`",
+            &format!(
+                "#[clippy::version = \"{version}\"]\n    \
+                (\"{}\", \"{}\"),\n    ",
+                lint.old_name, lint.new_name,
+            ),
+        )
+    });
+
     renamed_lints.push(lint);
     renamed_lints.sort_by(|lhs, rhs| {
         lhs.new_name
@@ -222,11 +225,6 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) {
             .then_with(|| lhs.old_name.cmp(&rhs.old_name))
     });
 
-    write_file(
-        Path::new("clippy_lints/src/renamed_lints.rs"),
-        &gen_renamed_lints_list(&renamed_lints),
-    );
-
     if uplift {
         write_file(Path::new("tests/ui/rename.rs"), &gen_renamed_lints_test(&renamed_lints));
         println!(
@@ -293,7 +291,8 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) {
 
         // Don't change `clippy_utils/src/renamed_lints.rs` here as it would try to edit the lint being
         // renamed.
-        for (_, file) in clippy_lints_src_files().filter(|(rel_path, _)| rel_path != OsStr::new("renamed_lints.rs")) {
+        for (_, file) in clippy_lints_src_files().filter(|(rel_path, _)| rel_path != OsStr::new("deprecated_lints.rs"))
+        {
             rewrite_file(file.path(), |s| replace_ident_like(s, replacements));
         }
 
@@ -304,7 +303,6 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) {
     println!("note: `cargo uitest` still needs to be run to update the test results");
 }
 
-const DEFAULT_DEPRECATION_REASON: &str = "default deprecation note";
 /// Runs the `deprecate` command
 ///
 /// This does the following:
@@ -314,33 +312,16 @@ const DEFAULT_DEPRECATION_REASON: &str = "default deprecation note";
 /// # Panics
 ///
 /// If a file path could not read from or written to
-pub fn deprecate(name: &str, reason: Option<&str>) {
-    fn finish(
-        (lints, mut deprecated_lints, renamed_lints): (Vec<Lint>, Vec<DeprecatedLint>, Vec<RenamedLint>),
-        name: &str,
-        reason: &str,
-    ) {
-        deprecated_lints.push(DeprecatedLint {
-            name: name.to_string(),
-            reason: reason.to_string(),
-            declaration_range: Range::default(),
-        });
-
-        generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints);
-        println!("info: `{name}` has successfully been deprecated");
-
-        if reason == DEFAULT_DEPRECATION_REASON {
-            println!("note: the deprecation reason must be updated in `clippy_lints/src/deprecated_lints.rs`");
-        }
-        println!("note: you must run `cargo uitest` to update the test results");
-    }
-
-    let reason = reason.unwrap_or(DEFAULT_DEPRECATION_REASON);
-    let name_lower = name.to_lowercase();
-    let name_upper = name.to_uppercase();
+pub fn deprecate(name: &str, reason: &str) {
+    let prefixed_name = if name.starts_with("clippy::") {
+        name.to_owned()
+    } else {
+        format!("clippy::{name}")
+    };
+    let stripped_name = &prefixed_name[8..];
 
-    let (mut lints, deprecated_lints, renamed_lints) = gather_all();
-    let Some(lint) = lints.iter().find(|l| l.name == name_lower) else {
+    let (mut lints, mut deprecated_lints, renamed_lints) = gather_all();
+    let Some(lint) = lints.iter().find(|l| l.name == stripped_name) else {
         eprintln!("error: failed to find lint `{name}`");
         return;
     };
@@ -357,13 +338,27 @@ pub fn deprecate(name: &str, reason: Option<&str>) {
 
     let deprecated_lints_path = &*clippy_project_root().join("clippy_lints/src/deprecated_lints.rs");
 
-    if remove_lint_declaration(&name_lower, &mod_path, &mut lints).unwrap_or(false) {
-        declare_deprecated(&name_upper, deprecated_lints_path, reason).unwrap();
-        finish((lints, deprecated_lints, renamed_lints), name, reason);
-        return;
-    }
+    if remove_lint_declaration(stripped_name, &mod_path, &mut lints).unwrap_or(false) {
+        let version = crate::new_lint::get_stabilization_version();
+        rewrite_file(deprecated_lints_path, |s| {
+            insert_at_marker(
+                s,
+                "// end deprecated lints. used by `cargo dev deprecate_lint`",
+                &format!("#[clippy::version = \"{version}\"]\n    (\"{prefixed_name}\", \"{reason}\"),\n    ",),
+            )
+        });
+
+        deprecated_lints.push(DeprecatedLint {
+            name: prefixed_name,
+            reason: reason.into(),
+        });
 
-    eprintln!("error: lint not found");
+        generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints);
+        println!("info: `{name}` has successfully been deprecated");
+        println!("note: you must run `cargo uitest` to update the test results");
+    } else {
+        eprintln!("error: lint not found");
+    }
 }
 
 fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec<Lint>) -> io::Result<bool> {
@@ -377,14 +372,14 @@ fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec<Lint>) -> io
 
         // Some lints have their own directories, delete them
         if path.is_dir() {
-            fs::remove_dir_all(path).ok();
+            let _ = fs::remove_dir_all(path);
             return;
         }
 
         // Remove all related test files
-        fs::remove_file(path.with_extension("rs")).ok();
-        fs::remove_file(path.with_extension("stderr")).ok();
-        fs::remove_file(path.with_extension("fixed")).ok();
+        let _ = fs::remove_file(path.with_extension("rs"));
+        let _ = fs::remove_file(path.with_extension("stderr"));
+        let _ = fs::remove_file(path.with_extension("fixed"));
     }
 
     fn remove_impl_lint_pass(lint_name_upper: &str, content: &mut String) {
@@ -427,7 +422,7 @@ fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec<Lint>) -> io
                     lint_mod_path.set_file_name(name);
                     lint_mod_path.set_extension("rs");
 
-                    fs::remove_file(lint_mod_path).ok();
+                    let _ = fs::remove_file(lint_mod_path);
                 }
 
                 let mut content =
@@ -465,37 +460,6 @@ fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec<Lint>) -> io
     Ok(false)
 }
 
-fn declare_deprecated(name: &str, path: &Path, reason: &str) -> io::Result<()> {
-    let mut file = OpenOptions::new().write(true).open(path)?;
-
-    file.seek(SeekFrom::End(0))?;
-
-    let version = crate::new_lint::get_stabilization_version();
-    let deprecation_reason = if reason == DEFAULT_DEPRECATION_REASON {
-        "TODO"
-    } else {
-        reason
-    };
-
-    writedoc!(
-        file,
-        "
-
-        declare_deprecated_lint! {{
-            /// ### What it does
-            /// Nothing. This lint has been deprecated.
-            ///
-            /// ### Deprecation reason
-            /// {deprecation_reason}
-            #[clippy::version = \"{version}\"]
-            pub {name},
-            \"{reason}\"
-        }}
-
-        "
-    )
-}
-
 /// Replace substrings if they aren't bordered by identifier characters. Returns `None` if there
 /// were no replacements.
 fn replace_ident_like(contents: &str, replacements: &[(&str, &str)]) -> Option<String> {
@@ -604,14 +568,12 @@ impl Lint {
 struct DeprecatedLint {
     name: String,
     reason: String,
-    declaration_range: Range<usize>,
 }
 impl DeprecatedLint {
-    fn new(name: &str, reason: &str, declaration_range: Range<usize>) -> Self {
+    fn new(name: &str, reason: &str) -> Self {
         Self {
-            name: name.to_lowercase(),
+            name: remove_line_splices(name),
             reason: remove_line_splices(reason),
-            declaration_range,
         }
     }
 }
@@ -629,28 +591,6 @@ impl RenamedLint {
     }
 }
 
-/// Generates the `register_removed` code
-#[must_use]
-fn gen_deprecated(lints: &[DeprecatedLint]) -> String {
-    let mut output = GENERATED_FILE_COMMENT.to_string();
-    output.push_str("{\n");
-    for lint in lints {
-        let _: fmt::Result = write!(
-            output,
-            concat!(
-                "    store.register_removed(\n",
-                "        \"clippy::{}\",\n",
-                "        \"{}\",\n",
-                "    );\n"
-            ),
-            lint.name, lint.reason,
-        );
-    }
-    output.push_str("}\n");
-
-    output
-}
-
 /// Generates the code for registering lints
 #[must_use]
 fn gen_declared_lints<'a>(
@@ -680,7 +620,7 @@ fn gen_declared_lints<'a>(
 fn gen_deprecated_lints_test(lints: &[DeprecatedLint]) -> String {
     let mut res: String = GENERATED_FILE_COMMENT.into();
     for lint in lints {
-        writeln!(res, "#![warn(clippy::{})]", lint.name).unwrap();
+        writeln!(res, "#![warn({})] //~ ERROR: lint `{}`", lint.name, lint.name).unwrap();
     }
     res.push_str("\nfn main() {}\n");
     res
@@ -699,27 +639,13 @@ fn gen_renamed_lints_test(lints: &[RenamedLint]) -> String {
     seen_lints.clear();
     for lint in lints {
         if seen_lints.insert(&lint.old_name) {
-            writeln!(res, "#![warn({})]", lint.old_name).unwrap();
+            writeln!(res, "#![warn({})] //~ ERROR: lint `{}`", lint.old_name, lint.old_name).unwrap();
         }
     }
     res.push_str("\nfn main() {}\n");
     res
 }
 
-fn gen_renamed_lints_list(lints: &[RenamedLint]) -> String {
-    const HEADER: &str = "\
-        // This file is managed by `cargo dev rename_lint`. Prefer using that when possible.\n\n\
-        #[rustfmt::skip]\n\
-        pub static RENAMED_LINTS: &[(&str, &str)] = &[\n";
-
-    let mut res = String::from(HEADER);
-    for lint in lints {
-        writeln!(res, "    (\"{}\", \"{}\"),", lint.old_name, lint.new_name).unwrap();
-    }
-    res.push_str("];\n");
-    res
-}
-
 /// Gathers all lints defined in `clippy_lints/src`
 fn gather_all() -> (Vec<Lint>, Vec<DeprecatedLint>, Vec<RenamedLint>) {
     let mut lints = Vec::with_capacity(1000);
@@ -744,10 +670,10 @@ fn gather_all() -> (Vec<Lint>, Vec<DeprecatedLint>, Vec<RenamedLint>) {
             module.strip_suffix(".rs").unwrap_or(&module)
         };
 
-        match module {
-            "deprecated_lints" => parse_deprecated_contents(&contents, &mut deprecated_lints),
-            "renamed_lints" => parse_renamed_contents(&contents, &mut renamed_lints),
-            _ => parse_contents(&contents, module, &mut lints),
+        if module == "deprecated_lints" {
+            parse_deprecated_contents(&contents, &mut deprecated_lints, &mut renamed_lints);
+        } else {
+            parse_contents(&contents, module, &mut lints);
         }
     }
     (lints, deprecated_lints, renamed_lints)
@@ -848,54 +774,37 @@ fn parse_contents(contents: &str, module: &str, lints: &mut Vec<Lint>) {
 }
 
 /// Parse a source file looking for `declare_deprecated_lint` macro invocations.
-fn parse_deprecated_contents(contents: &str, lints: &mut Vec<DeprecatedLint>) {
-    let mut offset = 0usize;
-    let mut iter = tokenize(contents).map(|t| {
-        let range = offset..offset + t.len as usize;
-        offset = range.end;
-
-        LintDeclSearchResult {
-            token_kind: t.kind,
-            content: &contents[range.clone()],
-            range,
-        }
-    });
+fn parse_deprecated_contents(contents: &str, deprecated: &mut Vec<DeprecatedLint>, renamed: &mut Vec<RenamedLint>) {
+    let Some((_, contents)) = contents.split_once("\ndeclare_with_version! { DEPRECATED") else {
+        return;
+    };
+    let Some((deprecated_src, renamed_src)) = contents.split_once("\ndeclare_with_version! { RENAMED") else {
+        return;
+    };
 
-    while let Some(LintDeclSearchResult { range, .. }) = iter.find(
-        |LintDeclSearchResult {
-             token_kind, content, ..
-         }| token_kind == &TokenKind::Ident && *content == "declare_deprecated_lint",
-    ) {
-        let start = range.start;
+    for line in deprecated_src.lines() {
+        let mut offset = 0usize;
+        let mut iter = tokenize(line).map(|t| {
+            let range = offset..offset + t.len as usize;
+            offset = range.end;
 
-        let mut iter = iter.by_ref().filter(|LintDeclSearchResult { ref token_kind, .. }| {
-            !matches!(token_kind, TokenKind::Whitespace | TokenKind::LineComment { .. })
+            LintDeclSearchResult {
+                token_kind: t.kind,
+                content: &line[range.clone()],
+                range,
+            }
         });
+
         let (name, reason) = match_tokens!(
             iter,
-            // !{
-            Bang OpenBrace
-            // #[clippy::version = "version"]
-            Pound OpenBracket Ident Colon Colon Ident Eq Literal{..} CloseBracket
-            // pub LINT_NAME,
-            Ident Ident(name) Comma
-            // "description"
-            Literal{kind: LiteralKind::Str{..},..}(reason)
+            // ("old_name",
+            Whitespace OpenParen Literal{kind: LiteralKind::Str{..},..}(name) Comma
+            // "new_name"),
+            Whitespace Literal{kind: LiteralKind::Str{..},..}(reason) CloseParen Comma
         );
-
-        if let Some(LintDeclSearchResult {
-            token_kind: TokenKind::CloseBrace,
-            range,
-            ..
-        }) = iter.next()
-        {
-            lints.push(DeprecatedLint::new(name, reason, start..range.end));
-        }
+        deprecated.push(DeprecatedLint::new(name, reason));
     }
-}
-
-fn parse_renamed_contents(contents: &str, lints: &mut Vec<RenamedLint>) {
-    for line in contents.lines() {
+    for line in renamed_src.lines() {
         let mut offset = 0usize;
         let mut iter = tokenize(line).map(|t| {
             let range = offset..offset + t.len as usize;
@@ -915,7 +824,7 @@ fn parse_renamed_contents(contents: &str, lints: &mut Vec<RenamedLint>) {
             // "new_name"),
             Whitespace Literal{kind: LiteralKind::Str{..},..}(new_name) CloseParen Comma
         );
-        lints.push(RenamedLint::new(old_name, new_name));
+        renamed.push(RenamedLint::new(old_name, new_name));
     }
 }
 
@@ -1015,6 +924,12 @@ fn panic_file(error: io::Error, name: &Path, action: &str) -> ! {
     panic!("failed to {action} file `{}`: {error}", name.display())
 }
 
+fn insert_at_marker(text: &str, marker: &str, new_text: &str) -> Option<String> {
+    let i = text.find(marker)?;
+    let (pre, post) = text.split_at(i);
+    Some([pre, new_text, post].into_iter().collect())
+}
+
 fn rewrite_file(path: &Path, f: impl FnOnce(&str) -> Option<String>) {
     let mut file = OpenOptions::new()
         .write(true)
@@ -1085,31 +1000,6 @@ mod tests {
     }
 
     #[test]
-    fn test_parse_deprecated_contents() {
-        static DEPRECATED_CONTENTS: &str = r#"
-            /// some doc comment
-            declare_deprecated_lint! {
-                #[clippy::version = "I'm a version"]
-                pub SHOULD_ASSERT_EQ,
-                "`assert!()` will be more flexible with RFC 2011"
-            }
-        "#;
-
-        let mut result = Vec::new();
-        parse_deprecated_contents(DEPRECATED_CONTENTS, &mut result);
-        for r in &mut result {
-            r.declaration_range = Range::default();
-        }
-
-        let expected = vec![DeprecatedLint::new(
-            "should_assert_eq",
-            "\"`assert!()` will be more flexible with RFC 2011\"",
-            Range::default(),
-        )];
-        assert_eq!(expected, result);
-    }
-
-    #[test]
     fn test_usable_lints() {
         let lints = vec![
             Lint::new(
@@ -1177,34 +1067,4 @@ mod tests {
         );
         assert_eq!(expected, Lint::by_lint_group(lints.into_iter()));
     }
-
-    #[test]
-    fn test_gen_deprecated() {
-        let lints = vec![
-            DeprecatedLint::new(
-                "should_assert_eq",
-                "\"has been superseded by should_assert_eq2\"",
-                Range::default(),
-            ),
-            DeprecatedLint::new("another_deprecated", "\"will be removed\"", Range::default()),
-        ];
-
-        let expected = GENERATED_FILE_COMMENT.to_string()
-            + &[
-                "{",
-                "    store.register_removed(",
-                "        \"clippy::should_assert_eq\",",
-                "        \"has been superseded by should_assert_eq2\",",
-                "    );",
-                "    store.register_removed(",
-                "        \"clippy::another_deprecated\",",
-                "        \"will be removed\",",
-                "    );",
-                "}",
-            ]
-            .join("\n")
-            + "\n";
-
-        assert_eq!(expected, gen_deprecated(&lints));
-    }
 }
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index eb04c006f89..99ed93468a0 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -32,7 +32,6 @@ url = "2.2"
 walkdir = "2.3"
 
 [features]
-deny-warnings = ["clippy_config/deny-warnings", "clippy_utils/deny-warnings"]
 # build clippy with internal lints enabled, off by default
 internal = ["serde_json", "tempfile", "regex"]
 
diff --git a/src/tools/clippy/clippy_lints/src/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs
index e6d52bcef71..3b4cc113480 100644
--- a/src/tools/clippy/clippy_lints/src/approx_const.rs
+++ b/src/tools/clippy/clippy_lints/src/approx_const.rs
@@ -97,7 +97,7 @@ impl ApproxConstant {
                         cx,
                         APPROX_CONSTANT,
                         e.span,
-                        format!("approximate value of `{module}::consts::{}` found", &name),
+                        format!("approximate value of `{module}::consts::{name}` found"),
                         None,
                         "consider using the constant directly",
                     );
diff --git a/src/tools/clippy/clippy_lints/src/as_conversions.rs b/src/tools/clippy/clippy_lints/src/as_conversions.rs
index cfa25005a05..fefd8195f8e 100644
--- a/src/tools/clippy/clippy_lints/src/as_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/as_conversions.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_from_proc_macro;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -52,13 +52,15 @@ impl<'tcx> LateLintPass<'tcx> for AsConversions {
             && !in_external_macro(cx.sess(), expr.span)
             && !is_from_proc_macro(cx, expr)
         {
-            span_lint_and_help(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 AS_CONVERSIONS,
                 expr.span,
                 "using a potentially dangerous silent `as` conversion",
-                None,
-                "consider using a safe wrapper for this conversion",
+                |diag| {
+                    diag.help("consider using a safe wrapper for this conversion");
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/asm_syntax.rs b/src/tools/clippy/clippy_lints/src/asm_syntax.rs
index 0db1456d40b..69a8eb7d94e 100644
--- a/src/tools/clippy/clippy_lints/src/asm_syntax.rs
+++ b/src/tools/clippy/clippy_lints/src/asm_syntax.rs
@@ -1,6 +1,6 @@
 use std::fmt;
 
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_ast::ast::{Expr, ExprKind, InlineAsmOptions};
 use rustc_ast::{InlineAsm, Item, ItemKind};
 use rustc_lint::{EarlyContext, EarlyLintPass, Lint, LintContext};
@@ -49,14 +49,10 @@ fn check_asm_syntax(
         };
 
         if style == check_for {
-            span_lint_and_help(
-                cx,
-                lint,
-                span,
-                format!("{style} x86 assembly syntax used"),
-                None,
-                format!("use {} x86 assembly syntax", !style),
-            );
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(cx, lint, span, format!("{style} x86 assembly syntax used"), |diag| {
+                diag.help(format!("use {} x86 assembly syntax", !style));
+            });
         }
     }
 }
@@ -98,13 +94,13 @@ declare_lint_pass!(InlineAsmX86IntelSyntax => [INLINE_ASM_X86_INTEL_SYNTAX]);
 impl EarlyLintPass for InlineAsmX86IntelSyntax {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
         if let ExprKind::InlineAsm(inline_asm) = &expr.kind {
-            check_asm_syntax(Self::get_lints()[0], cx, inline_asm, expr.span, AsmStyle::Intel);
+            check_asm_syntax(INLINE_ASM_X86_INTEL_SYNTAX, cx, inline_asm, expr.span, AsmStyle::Intel);
         }
     }
 
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
         if let ItemKind::GlobalAsm(inline_asm) = &item.kind {
-            check_asm_syntax(Self::get_lints()[0], cx, inline_asm, item.span, AsmStyle::Intel);
+            check_asm_syntax(INLINE_ASM_X86_INTEL_SYNTAX, cx, inline_asm, item.span, AsmStyle::Intel);
         }
     }
 }
@@ -146,13 +142,13 @@ declare_lint_pass!(InlineAsmX86AttSyntax => [INLINE_ASM_X86_ATT_SYNTAX]);
 impl EarlyLintPass for InlineAsmX86AttSyntax {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
         if let ExprKind::InlineAsm(inline_asm) = &expr.kind {
-            check_asm_syntax(Self::get_lints()[0], cx, inline_asm, expr.span, AsmStyle::Att);
+            check_asm_syntax(INLINE_ASM_X86_ATT_SYNTAX, cx, inline_asm, expr.span, AsmStyle::Att);
         }
     }
 
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
         if let ItemKind::GlobalAsm(inline_asm) = &item.kind {
-            check_asm_syntax(Self::get_lints()[0], cx, inline_asm, item.span, AsmStyle::Att);
+            check_asm_syntax(INLINE_ASM_X86_ATT_SYNTAX, cx, inline_asm, item.span, AsmStyle::Att);
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
index ed4cdce8cb8..7eaac80f969 100644
--- a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
+++ b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::is_inside_always_const_context;
 use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn};
@@ -43,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants {
         let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn) else {
             return;
         };
-        let Some(Constant::Bool(val)) = constant(cx, cx.typeck_results(), condition) else {
+        let Some(Constant::Bool(val)) = ConstEvalCtxt::new(cx).eval(condition) else {
             return;
         };
 
diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
index 7217686dcca..f1cb4a05af8 100644
--- a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
+++ b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn};
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::{has_debug_impl, is_copy, is_type_diagnostic_item};
@@ -68,39 +68,28 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
                     return;
                 }
             }
-            let semicolon = if is_expr_final_block_expr(cx.tcx, e) { ";" } else { "" };
-            let mut app = Applicability::MachineApplicable;
-            match method_segment.ident.as_str() {
+            let (message, replacement) = match method_segment.ident.as_str() {
                 "is_ok" if type_suitable_to_unwrap(cx, args.type_at(1)) => {
-                    span_lint_and_sugg(
-                        cx,
-                        ASSERTIONS_ON_RESULT_STATES,
-                        macro_call.span,
-                        "called `assert!` with `Result::is_ok`",
-                        "replace with",
-                        format!(
-                            "{}.unwrap(){semicolon}",
-                            snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0
-                        ),
-                        app,
-                    );
+                    ("called `assert!` with `Result::is_ok`", "unwrap")
                 },
                 "is_err" if type_suitable_to_unwrap(cx, args.type_at(0)) => {
-                    span_lint_and_sugg(
-                        cx,
-                        ASSERTIONS_ON_RESULT_STATES,
-                        macro_call.span,
-                        "called `assert!` with `Result::is_err`",
-                        "replace with",
-                        format!(
-                            "{}.unwrap_err(){semicolon}",
-                            snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0
-                        ),
-                        app,
-                    );
+                    ("called `assert!` with `Result::is_err`", "unwrap_err")
                 },
-                _ => (),
+                _ => return,
             };
+            span_lint_and_then(cx, ASSERTIONS_ON_RESULT_STATES, macro_call.span, message, |diag| {
+                let semicolon = if is_expr_final_block_expr(cx.tcx, e) { ";" } else { "" };
+                let mut app = Applicability::MachineApplicable;
+                diag.span_suggestion(
+                    macro_call.span,
+                    "replace with",
+                    format!(
+                        "{}.{replacement}(){semicolon}",
+                        snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0
+                    ),
+                    app,
+                );
+            });
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
index 03f777600f0..6e336efbb90 100644
--- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs
+++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
@@ -227,9 +227,22 @@ fn build_sugg<'tcx>(
             match call_kind {
                 CallKind::Method => {
                     let receiver_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind {
-                        // `*lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)`
-                        Sugg::hir_with_applicability(cx, ref_expr, "_", app)
+                        // If `ref_expr` is a reference, we can remove the dereference operator (`*`) to make
+                        // the generated code a bit simpler. In other cases, we don't do this special case, to avoid
+                        // having to deal with Deref (https://github.com/rust-lang/rust-clippy/issues/12437).
+
+                        let ty = cx.typeck_results().expr_ty(ref_expr);
+                        if ty.is_ref() {
+                            // Apply special case, remove `*`
+                            // `*lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)`
+                            Sugg::hir_with_applicability(cx, ref_expr, "_", app)
+                        } else {
+                            // Keep the original lhs
+                            // `*lhs = self_expr.clone();` -> `(*lhs).clone_from(self_expr)`
+                            Sugg::hir_with_applicability(cx, lhs, "_", app)
+                        }
                     } else {
+                        // Keep the original lhs
                         // `lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)`
                         Sugg::hir_with_applicability(cx, lhs, "_", app)
                     }
@@ -249,8 +262,16 @@ fn build_sugg<'tcx>(
                 },
                 CallKind::Ufcs => {
                     let self_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind {
-                        // `*lhs = Clone::clone(self_expr);` -> `Clone::clone_from(lhs, self_expr)`
-                        Sugg::hir_with_applicability(cx, ref_expr, "_", app)
+                        // See special case of removing `*` in method handling above
+                        let ty = cx.typeck_results().expr_ty(ref_expr);
+                        if ty.is_ref() {
+                            // `*lhs = Clone::clone(self_expr);` -> `Clone::clone_from(lhs, self_expr)`
+                            Sugg::hir_with_applicability(cx, ref_expr, "_", app)
+                        } else {
+                            // `*lhs = Clone::clone(self_expr);` -> `Clone::clone_from(&mut *lhs, self_expr)`
+                            // mut_addr_deref is used to avoid unnecessary parentheses around `*lhs`
+                            Sugg::hir_with_applicability(cx, ref_expr, "_", app).mut_addr_deref()
+                        }
                     } else {
                         // `lhs = Clone::clone(self_expr);` -> `Clone::clone_from(&mut lhs, self_expr)`
                         Sugg::hir_with_applicability(cx, lhs, "_", app).mut_addr()
diff --git a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs
index df9994086cd..a5a7b9f74a6 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs
@@ -1,5 +1,5 @@
 use super::ALLOW_ATTRIBUTES;
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_from_proc_macro;
 use rustc_ast::{AttrStyle, Attribute};
 use rustc_errors::Applicability;
@@ -13,14 +13,14 @@ pub fn check<'cx>(cx: &LateContext<'cx>, attr: &'cx Attribute) {
         && 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,
-        );
+        #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+        span_lint_and_then(cx, ALLOW_ATTRIBUTES, ident.span, "#[allow] attribute found", |diag| {
+            diag.span_suggestion(
+                ident.span,
+                "replace it with",
+                "expect",
+                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 4b42616a636..4ab97118df1 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
@@ -1,5 +1,5 @@
 use super::{Attribute, ALLOW_ATTRIBUTES_WITHOUT_REASON};
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_from_proc_macro;
 use rustc_ast::{MetaItemKind, NestedMetaItem};
 use rustc_lint::{LateContext, LintContext};
@@ -21,12 +21,14 @@ pub(super) fn check<'cx>(cx: &LateContext<'cx>, name: Symbol, items: &[NestedMet
         return;
     }
 
-    span_lint_and_help(
+    #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+    span_lint_and_then(
         cx,
         ALLOW_ATTRIBUTES_WITHOUT_REASON,
         attr.span,
         format!("`{}` attribute without specifying a reason", name.as_str()),
-        None,
-        "try adding a reason at the end with `, reason = \"..\"`",
+        |diag| {
+            diag.help("try adding a reason at the end with `, reason = \"..\"`");
+        },
     );
 }
diff --git a/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs b/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs
index 561ca9bd986..612712d1684 100644
--- a/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs
+++ b/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{in_constant, is_else_clause};
+use clippy_utils::{is_else_clause, is_in_const_context};
 use rustc_ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
@@ -52,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for BoolToIntWithIf {
             && let Some(else_lit) = as_int_bool_lit(else_)
             && then_lit != else_lit
             && !expr.span.from_expansion()
-            && !in_constant(cx, expr.hir_id)
+            && !is_in_const_context(cx)
         {
             let ty = cx.typeck_results().expr_ty(then);
             let mut applicability = Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs
index a1c6c0b608f..a2f48c18170 100644
--- a/src/tools/clippy/clippy_lints/src/booleans.rs
+++ b/src/tools/clippy/clippy_lints/src/booleans.rs
@@ -477,14 +477,12 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
             cx: self.cx,
         };
         if let Ok(expr) = h2q.run(e) {
-            if h2q.terminals.len() > 8 {
-                // QMC has exponentially slow behavior as the number of terminals increases
-                // 8 is reasonable, it takes approximately 0.2 seconds.
-                // See #825
+            let stats = terminal_stats(&expr);
+            if stats.ops > 7 {
+                // QMC has exponentially slow behavior as the number of ops increases.
+                // See #825, #13206
                 return;
             }
-
-            let stats = terminal_stats(&expr);
             let mut simplified = expr.simplify();
             for simple in Bool::Not(Box::new(expr)).simplify() {
                 match simple {
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
index ff460a3fd8e..bd3acc06f4b 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
@@ -1,6 +1,6 @@
 use clippy_config::msrvs::{self, Msrv};
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::in_constant;
+use clippy_utils::is_in_const_context;
 use clippy_utils::source::snippet_opt;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::is_isize_or_usize;
@@ -21,7 +21,7 @@ pub(super) fn check(
     cast_to_hir: &rustc_hir::Ty<'_>,
     msrv: &Msrv,
 ) {
-    if !should_lint(cx, expr, cast_from, cast_to, msrv) {
+    if !should_lint(cx, cast_from, cast_to, msrv) {
         return;
     }
 
@@ -70,9 +70,9 @@ pub(super) fn check(
     );
 }
 
-fn should_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, msrv: &Msrv) -> bool {
+fn should_lint(cx: &LateContext<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, msrv: &Msrv) -> bool {
     // Do not suggest using From in consts/statics until it is valid to do so (see #2267).
-    if in_constant(cx, expr.hir_id) {
+    if is_in_const_context(cx) {
         return false;
     }
 
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 5bc8692c289..464eabe5d9a 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
@@ -1,6 +1,6 @@
 use super::CAST_NAN_TO_INT;
 
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_note;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
@@ -20,7 +20,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) {
+    match ConstEvalCtxt::new(cx).eval(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(),
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
index 7c5acd1a678..102fe25fc67 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::expr_or_init;
 use clippy_utils::source::snippet;
@@ -15,7 +15,7 @@ use rustc_target::abi::IntegerType;
 use super::{utils, CAST_ENUM_TRUNCATION, CAST_POSSIBLE_TRUNCATION};
 
 fn constant_int(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u128> {
-    if let Some(Constant::Int(c)) = constant(cx, cx.typeck_results(), expr) {
+    if let Some(Constant::Int(c)) = ConstEvalCtxt::new(cx).eval(expr) {
         Some(c)
     } else {
         None
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
index 8bbd41b0db1..9daf237344a 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
@@ -1,7 +1,7 @@
 use std::convert::Infallible;
 use std::ops::ControlFlow;
 
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::visitors::{for_each_expr_without_closures, Descend};
 use clippy_utils::{method_chain_args, sext};
@@ -88,7 +88,7 @@ fn get_const_signed_int_eval<'cx>(
 ) -> Option<i128> {
     let ty = ty.into().unwrap_or_else(|| cx.typeck_results().expr_ty(expr));
 
-    if let Constant::Int(n) = constant(cx, cx.typeck_results(), expr)?
+    if let Constant::Int(n) = ConstEvalCtxt::new(cx).eval(expr)?
         && let ty::Int(ity) = *ty.kind()
     {
         return Some(sext(cx.tcx, n, ity));
@@ -103,7 +103,7 @@ fn get_const_unsigned_int_eval<'cx>(
 ) -> Option<u128> {
     let ty = ty.into().unwrap_or_else(|| cx.typeck_results().expr_ty(expr));
 
-    if let Constant::Int(n) = constant(cx, cx.typeck_results(), expr)?
+    if let Constant::Int(n) = ConstEvalCtxt::new(cx).eval(expr)?
         && let ty::Uint(_ity) = *ty.kind()
     {
         return Some(n);
diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs
index 826589bf303..75de53f73ee 100644
--- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs
@@ -1,6 +1,6 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_with_applicability;
-use rustc_errors::Applicability;
+use rustc_errors::{Applicability, SuggestionStyle};
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, Ty};
@@ -14,21 +14,24 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
         _ => { /* continue to checks */ },
     }
 
-    match cast_from.kind() {
-        ty::FnDef(..) | ty::FnPtr(_) => {
-            let mut applicability = Applicability::MaybeIncorrect;
-            let from_snippet = snippet_with_applicability(cx, cast_expr.span, "..", &mut applicability);
+    if let ty::FnDef(..) | ty::FnPtr(_) = cast_from.kind() {
+        let mut applicability = Applicability::MaybeIncorrect;
+        let from_snippet = snippet_with_applicability(cx, cast_expr.span, "..", &mut applicability);
 
-            span_lint_and_sugg(
-                cx,
-                FN_TO_NUMERIC_CAST_ANY,
-                expr.span,
-                format!("casting function pointer `{from_snippet}` to `{cast_to}`"),
-                "did you mean to invoke the function?",
-                format!("{from_snippet}() as {cast_to}"),
-                applicability,
-            );
-        },
-        _ => {},
+        span_lint_and_then(
+            cx,
+            FN_TO_NUMERIC_CAST_ANY,
+            expr.span,
+            format!("casting function pointer `{from_snippet}` to `{cast_to}`"),
+            |diag| {
+                diag.span_suggestion_with_style(
+                    expr.span,
+                    "did you mean to invoke the function?",
+                    format!("{from_snippet}() as {cast_to}"),
+                    applicability,
+                    SuggestionStyle::ShowAlways,
+                );
+            },
+        );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/casts/zero_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/zero_ptr.rs
index 5071af5ecb9..3c1c7d2dc3a 100644
--- a/src/tools/clippy/clippy_lints/src/casts/zero_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/zero_ptr.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_opt;
-use clippy_utils::{in_constant, is_integer_literal, std_or_core};
+use clippy_utils::{is_in_const_context, is_integer_literal, std_or_core};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, Mutability, Ty, TyKind};
 use rustc_lint::LateContext;
@@ -10,7 +10,7 @@ use super::ZERO_PTR;
 pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, from: &Expr<'_>, to: &Ty<'_>) {
     if let TyKind::Ptr(ref mut_ty) = to.kind
         && is_integer_literal(from, 0)
-        && !in_constant(cx, from.hir_id)
+        && !is_in_const_context(cx)
         && let Some(std_or_core) = std_or_core(cx)
     {
         let (msg, sugg_fn) = match mut_ty.mutbl {
diff --git a/src/tools/clippy/clippy_lints/src/checked_conversions.rs b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
index 0b1ab5411bf..1711565fca8 100644
--- a/src/tools/clippy/clippy_lints/src/checked_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
@@ -4,7 +4,7 @@ use clippy_config::msrvs::{self, Msrv};
 use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{in_constant, is_integer_literal, SpanlessEq};
+use clippy_utils::{is_in_const_context, is_integer_literal, SpanlessEq};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, QPath, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -67,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for CheckedConversions {
                 _ => return,
             }
             && !in_external_macro(cx.sess(), item.span)
-            && !in_constant(cx, item.hir_id)
+            && !is_in_const_context(cx)
             && self.msrv.meets(msrvs::TRY_FROM)
             && let Some(cv) = match op2 {
                 // todo: check for case signed -> larger unsigned == only x >= 0
diff --git a/src/tools/clippy/clippy_lints/src/comparison_chain.rs b/src/tools/clippy/clippy_lints/src/comparison_chain.rs
index 2c23c0b4f15..5d78744e9b5 100644
--- a/src/tools/clippy/clippy_lints/src/comparison_chain.rs
+++ b/src/tools/clippy/clippy_lints/src/comparison_chain.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::ty::implements_trait;
-use clippy_utils::{if_sequence, in_constant, is_else_clause, SpanlessEq};
+use clippy_utils::{if_sequence, is_else_clause, is_in_const_context, SpanlessEq};
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
@@ -68,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain {
             return;
         }
 
-        if in_constant(cx, expr.hir_id) {
+        if is_in_const_context(cx) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/create_dir.rs b/src/tools/clippy/clippy_lints/src/create_dir.rs
index 27c00948a8f..b49a977dbea 100644
--- a/src/tools/clippy/clippy_lints/src/create_dir.rs
+++ b/src/tools/clippy/clippy_lints/src/create_dir.rs
@@ -1,6 +1,6 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet;
-use rustc_errors::Applicability;
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::snippet_with_applicability;
+use rustc_errors::{Applicability, SuggestionStyle};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
@@ -39,14 +39,24 @@ impl LateLintPass<'_> for CreateDir {
             && let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id()
             && cx.tcx.is_diagnostic_item(sym::fs_create_dir, def_id)
         {
-            span_lint_and_sugg(
+            span_lint_and_then(
                 cx,
                 CREATE_DIR,
                 expr.span,
                 "calling `std::fs::create_dir` where there may be a better way",
-                "consider calling `std::fs::create_dir_all` instead",
-                format!("create_dir_all({})", snippet(cx, arg.span, "..")),
-                Applicability::MaybeIncorrect,
+                |diag| {
+                    let mut app = Applicability::MaybeIncorrect;
+                    diag.span_suggestion_with_style(
+                        expr.span,
+                        "consider calling `std::fs::create_dir_all` instead",
+                        format!(
+                            "create_dir_all({})",
+                            snippet_with_applicability(cx, arg.span, "..", &mut app)
+                        ),
+                        app,
+                        SuggestionStyle::ShowAlways,
+                    );
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/dbg_macro.rs b/src/tools/clippy/clippy_lints/src/dbg_macro.rs
index 788c6f3ada2..93c8fff05e9 100644
--- a/src/tools/clippy/clippy_lints/src/dbg_macro.rs
+++ b/src/tools/clippy/clippy_lints/src/dbg_macro.rs
@@ -1,5 +1,5 @@
 use clippy_config::Conf;
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_in_test;
 use clippy_utils::macros::{macro_backtrace, MacroCall};
 use clippy_utils::source::snippet_with_applicability;
@@ -65,61 +65,67 @@ impl LateLintPass<'_> for DbgMacro {
             // allows `dbg!` in test code if allow-dbg-in-test is set to true in clippy.toml
             !(self.allow_dbg_in_tests && is_in_test(cx.tcx, expr.hir_id))
         {
-            let mut applicability = Applicability::MachineApplicable;
-
-            let (sugg_span, suggestion) = match expr.peel_drop_temps().kind {
-                // dbg!()
-                ExprKind::Block(..) => {
-                    // If the `dbg!` macro is a "free" statement and not contained within other expressions,
-                    // remove the whole statement.
-                    if let Node::Stmt(_) = cx.tcx.parent_hir_node(expr.hir_id)
-                        && let Some(semi_span) = cx.sess().source_map().mac_call_stmt_semi_span(macro_call.span)
-                    {
-                        (macro_call.span.to(semi_span), String::new())
-                    } else {
-                        (macro_call.span, String::from("()"))
-                    }
-                },
-                // dbg!(1)
-                ExprKind::Match(val, ..) => (
-                    macro_call.span,
-                    snippet_with_applicability(cx, val.span.source_callsite(), "..", &mut applicability).to_string(),
-                ),
-                // dbg!(2, 3)
-                ExprKind::Tup(
-                    [
-                        Expr {
-                            kind: ExprKind::Match(first, ..),
-                            ..
-                        },
-                        ..,
-                        Expr {
-                            kind: ExprKind::Match(last, ..),
-                            ..
-                        },
-                    ],
-                ) => {
-                    let snippet = snippet_with_applicability(
-                        cx,
-                        first.span.source_callsite().to(last.span.source_callsite()),
-                        "..",
-                        &mut applicability,
-                    );
-                    (macro_call.span, format!("({snippet})"))
-                },
-                _ => return,
-            };
-
             self.prev_ctxt = cur_syntax_ctxt;
 
-            span_lint_and_sugg(
+            span_lint_and_then(
                 cx,
                 DBG_MACRO,
-                sugg_span,
+                macro_call.span,
                 "the `dbg!` macro is intended as a debugging tool",
-                "remove the invocation before committing it to a version control system",
-                suggestion,
-                applicability,
+                |diag| {
+                    let mut applicability = Applicability::MachineApplicable;
+
+                    let (sugg_span, suggestion) = match expr.peel_drop_temps().kind {
+                        // dbg!()
+                        ExprKind::Block(..) => {
+                            // If the `dbg!` macro is a "free" statement and not contained within other expressions,
+                            // remove the whole statement.
+                            if let Node::Stmt(_) = cx.tcx.parent_hir_node(expr.hir_id)
+                                && let Some(semi_span) = cx.sess().source_map().mac_call_stmt_semi_span(macro_call.span)
+                            {
+                                (macro_call.span.to(semi_span), String::new())
+                            } else {
+                                (macro_call.span, String::from("()"))
+                            }
+                        },
+                        // dbg!(1)
+                        ExprKind::Match(val, ..) => (
+                            macro_call.span,
+                            snippet_with_applicability(cx, val.span.source_callsite(), "..", &mut applicability)
+                                .to_string(),
+                        ),
+                        // dbg!(2, 3)
+                        ExprKind::Tup(
+                            [
+                                Expr {
+                                    kind: ExprKind::Match(first, ..),
+                                    ..
+                                },
+                                ..,
+                                Expr {
+                                    kind: ExprKind::Match(last, ..),
+                                    ..
+                                },
+                            ],
+                        ) => {
+                            let snippet = snippet_with_applicability(
+                                cx,
+                                first.span.source_callsite().to(last.span.source_callsite()),
+                                "..",
+                                &mut applicability,
+                            );
+                            (macro_call.span, format!("({snippet})"))
+                        },
+                        _ => unreachable!(),
+                    };
+
+                    diag.span_suggestion(
+                        sugg_span,
+                        "remove the invocation before committing it to a version control system",
+                        suggestion,
+                        applicability,
+                    );
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 69f9eb6842b..3fb083dd833 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -14,8 +14,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     #[cfg(feature = "internal")]
     crate::utils::internal_lints::invalid_paths::INVALID_PATHS_INFO,
     #[cfg(feature = "internal")]
-    crate::utils::internal_lints::lint_without_lint_pass::DEFAULT_DEPRECATION_REASON_INFO,
-    #[cfg(feature = "internal")]
     crate::utils::internal_lints::lint_without_lint_pass::DEFAULT_LINT_INFO,
     #[cfg(feature = "internal")]
     crate::utils::internal_lints::lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE_INFO,
@@ -741,6 +739,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::unused_async::UNUSED_ASYNC_INFO,
     crate::unused_io_amount::UNUSED_IO_AMOUNT_INFO,
     crate::unused_peekable::UNUSED_PEEKABLE_INFO,
+    crate::unused_result_ok::UNUSED_RESULT_OK_INFO,
     crate::unused_rounding::UNUSED_ROUNDING_INFO,
     crate::unused_self::UNUSED_SELF_INFO,
     crate::unused_unit::UNUSED_UNIT_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs
index 72fa05be3cc..0b7279f2b36 100644
--- a/src/tools/clippy/clippy_lints/src/default.rs
+++ b/src/tools/clippy/clippy_lints/src/default.rs
@@ -221,7 +221,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
                         .map(ToString::to_string)
                         .collect::<Vec<_>>()
                         .join(", ");
-                    format!("{adt_def_ty_name}::<{}>", &tys_str)
+                    format!("{adt_def_ty_name}::<{tys_str}>")
                 } else {
                     binding_type.to_string()
                 };
diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
index 9af73db6849..a74b3a8c836 100644
--- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
+++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
@@ -92,20 +92,8 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
             let (suffix, is_float) = match lit_ty.kind() {
                 ty::Int(IntTy::I32) => ("i32", false),
                 ty::Float(FloatTy::F64) => ("f64", true),
-                // Default numeric fallback never results in other types.
                 _ => return,
             };
-
-            let src = if let Some(src) = snippet_opt(self.cx, lit.span) {
-                src
-            } else {
-                match lit.node {
-                    LitKind::Int(src, _) => format!("{src}"),
-                    LitKind::Float(src, _) => format!("{src}"),
-                    _ => return,
-                }
-            };
-            let sugg = numeric_literal::format(&src, Some(suffix), is_float);
             span_lint_hir_and_then(
                 self.cx,
                 DEFAULT_NUMERIC_FALLBACK,
@@ -113,6 +101,17 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
                 lit.span,
                 "default numeric fallback might occur",
                 |diag| {
+                    let src = if let Some(src) = snippet_opt(self.cx, lit.span) {
+                        src
+                    } else {
+                        match lit.node {
+                            LitKind::Int(src, _) => format!("{src}"),
+                            LitKind::Float(src, _) => format!("{src}"),
+                            _ => unreachable!("Default numeric fallback never results in other types"),
+                        }
+                    };
+
+                    let sugg = numeric_literal::format(&src, Some(suffix), is_float);
                     diag.span_suggestion(lit.span, "consider adding suffix", sugg, Applicability::MaybeIncorrect);
                 },
             );
diff --git a/src/tools/clippy/clippy_lints/src/default_union_representation.rs b/src/tools/clippy/clippy_lints/src/default_union_representation.rs
index 3fa9bad0d03..9f020d3081c 100644
--- a/src/tools/clippy/clippy_lints/src/default_union_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/default_union_representation.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_hir::{HirId, Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::layout::LayoutOf;
@@ -56,16 +56,18 @@ impl<'tcx> LateLintPass<'tcx> for DefaultUnionRepresentation {
             && is_union_with_two_non_zst_fields(cx, item)
             && !has_c_repr_attr(cx, item.hir_id())
         {
-            span_lint_and_help(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 DEFAULT_UNION_REPRESENTATION,
                 item.span,
                 "this union has the default representation",
-                None,
-                format!(
-                    "consider annotating `{}` with `#[repr(C)]` to explicitly specify memory layout",
-                    cx.tcx.def_path_str(item.owner_id)
-                ),
+                |diag| {
+                    diag.help(format!(
+                        "consider annotating `{}` with `#[repr(C)]` to explicitly specify memory layout",
+                        cx.tcx.def_path_str(item.owner_id)
+                    ));
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
index a0900f46f6a..0066ed64325 100644
--- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
@@ -1,243 +1,181 @@
-// NOTE: Entries should be created with `cargo dev deprecate`
-
-/// This struct fakes the `Lint` declaration that is usually created by `declare_lint!`. This
-/// enables the simple extraction of the metadata without changing the current deprecation
-/// declaration.
-pub struct ClippyDeprecatedLint {
-    #[allow(dead_code)]
-    pub desc: &'static str,
-}
-
-#[macro_export]
-macro_rules! declare_deprecated_lint {
-    { $(#[$attr:meta])* pub $name: ident, $reason: literal} => {
-        $(#[$attr])*
-        #[allow(dead_code)]
-        pub static $name: ClippyDeprecatedLint = ClippyDeprecatedLint {
-            desc: $reason
-        };
-    }
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// This used to check for `assert!(a == b)` and recommend
-    /// replacement with `assert_eq!(a, b)`, but this is no longer needed after RFC 2011.
+// This file is managed by `cargo dev rename_lint` and `cargo dev deprecate_lint`.
+// Prefer to use those when possible.
+
+macro_rules! declare_with_version {
+    ($name:ident($name_version:ident): &[$ty:ty] = &[$(
+        #[clippy::version = $version:literal]
+        $e:expr,
+    )*]) => {
+        pub static $name: &[$ty] = &[$($e),*];
+        #[allow(unused)]
+        pub static $name_version: &[&str] = &[$($version),*];
+    };
+}
+
+#[rustfmt::skip]
+declare_with_version! { DEPRECATED(DEPRECATED_VERSION): &[(&str, &str)] = &[
     #[clippy::version = "pre 1.29.0"]
-    pub SHOULD_ASSERT_EQ,
-    "`assert!()` will be more flexible with RFC 2011"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// This used to check for `Vec::extend`, which was slower than
-    /// `Vec::extend_from_slice`. Thanks to specialization, this is no longer true.
+    ("clippy::should_assert_eq", "`assert!(a == b)` can now print the values the same way `assert_eq!(a, b) can"),
     #[clippy::version = "pre 1.29.0"]
-    pub EXTEND_FROM_SLICE,
-    "`.extend_from_slice(_)` is a faster way to extend a Vec by a slice"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// `Range::step_by(0)` used to be linted since it's
-    /// an infinite iterator, which is better expressed by `iter::repeat`,
-    /// but the method has been removed for `Iterator::step_by` which panics
-    /// if given a zero
+    ("clippy::extend_from_slice", "`Vec::extend_from_slice` is no longer faster than `Vec::extend` due to specialization"),
     #[clippy::version = "pre 1.29.0"]
-    pub RANGE_STEP_BY_ZERO,
-    "`iterator.step_by(0)` panics nowadays"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// This used to check for `Vec::as_slice`, which was unstable with good
-    /// stable alternatives. `Vec::as_slice` has now been stabilized.
+    ("clippy::range_step_by_zero", "`Iterator::step_by(0)` now panics and is no longer an infinite iterator"),
     #[clippy::version = "pre 1.29.0"]
-    pub UNSTABLE_AS_SLICE,
-    "`Vec::as_slice` has been stabilized in 1.7"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// This used to check for `Vec::as_mut_slice`, which was unstable with good
-    /// stable alternatives. `Vec::as_mut_slice` has now been stabilized.
+    ("clippy::unstable_as_slice", "`Vec::as_slice` is now stable"),
     #[clippy::version = "pre 1.29.0"]
-    pub UNSTABLE_AS_MUT_SLICE,
-    "`Vec::as_mut_slice` has been stabilized in 1.7"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// This lint should never have applied to non-pointer types, as transmuting
-    /// between non-pointer types of differing alignment is well-defined behavior (it's semantically
-    /// equivalent to a memcpy). This lint has thus been refactored into two separate lints:
-    /// cast_ptr_alignment and transmute_ptr_to_ptr.
+    ("clippy::unstable_as_mut_slice", "`Vec::as_mut_slice` is now stable"),
     #[clippy::version = "pre 1.29.0"]
-    pub MISALIGNED_TRANSMUTE,
-    "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// This lint is too subjective, not having a good reason for being in clippy.
-    /// Additionally, compound assignment operators may be overloaded separately from their non-assigning
-    /// counterparts, so this lint may suggest a change in behavior or the code may not compile.
+    ("clippy::misaligned_transmute", "split into `clippy::cast_ptr_alignment` and `clippy::transmute_ptr_to_ptr`"),
     #[clippy::version = "1.30.0"]
-    pub ASSIGN_OPS,
-    "using compound assignment operators (e.g., `+=`) is harmless"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// The original rule will only lint for `if let`. After
-    /// making it support to lint `match`, naming as `if let` is not suitable for it.
-    /// So, this lint is deprecated.
+    ("clippy::assign_ops", "compound operators are harmless and linting on them is not in scope for clippy"),
     #[clippy::version = "pre 1.29.0"]
-    pub IF_LET_REDUNDANT_PATTERN_MATCHING,
-    "this lint has been changed to redundant_pattern_matching"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// This lint used to suggest replacing `let mut vec =
-    /// Vec::with_capacity(n); vec.set_len(n);` with `let vec = vec![0; n];`. The
-    /// replacement has very different performance characteristics so the lint is
-    /// deprecated.
-    #[clippy::version = "pre 1.29.0"]
-    pub UNSAFE_VECTOR_INITIALIZATION,
-    "the replacement suggested by this lint had substantially different behavior"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// This lint has been superseded by #[must_use] in rustc.
+    ("clippy::unsafe_vector_initialization", "the suggested alternative could be substantially slower"),
     #[clippy::version = "1.39.0"]
-    pub UNUSED_COLLECT,
-    "`collect` has been marked as #[must_use] in rustc and that covers all cases of this lint"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// Associated-constants are now preferred.
+    ("clippy::unused_collect", "`Iterator::collect` is now marked as `#[must_use]`"),
     #[clippy::version = "1.44.0"]
-    pub REPLACE_CONSTS,
-    "associated-constants `MIN`/`MAX` of integers are preferred to `{min,max}_value()` and module constants"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// The regex! macro does not exist anymore.
+    ("clippy::replace_consts", "`min_value` and `max_value` are now deprecated"),
     #[clippy::version = "1.47.0"]
-    pub REGEX_MACRO,
-    "the regex! macro has been removed from the regex crate in 2018"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// This lint has been replaced by `manual_find_map`, a
-    /// more specific lint.
-    #[clippy::version = "1.51.0"]
-    pub FIND_MAP,
-    "this lint has been replaced by `manual_find_map`, a more specific lint"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// This lint has been replaced by `manual_filter_map`, a
-    /// more specific lint.
-    #[clippy::version = "1.53.0"]
-    pub FILTER_MAP,
-    "this lint has been replaced by `manual_filter_map`, a more specific lint"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// The `avoid_breaking_exported_api` config option was added, which
-    /// enables the `enum_variant_names` lint for public items.
+    ("clippy::regex_macro", "the `regex!` macro was removed from the regex crate in 2018"),
     #[clippy::version = "1.54.0"]
-    pub PUB_ENUM_VARIANT_NAMES,
-    "set the `avoid-breaking-exported-api` config option to `false` to enable the `enum_variant_names` lint for public items"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// The `avoid_breaking_exported_api` config option was added, which
-    /// enables the `wrong_self_conversion` lint for public items.
+    ("clippy::pub_enum_variant_names", "`clippy::enum_variant_names` now covers this case via the `avoid-breaking-exported-api` config"),
     #[clippy::version = "1.54.0"]
-    pub WRONG_PUB_SELF_CONVENTION,
-    "set the `avoid-breaking-exported-api` config option to `false` to enable the `wrong_self_convention` lint for public items"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// This lint has been superseded by rustc's own [`unexpected_cfgs`] lint that is able to detect the `#[cfg(features)]` and `#[cfg(tests)]` typos.
-    ///
-    /// [`unexpected_cfgs`]: https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#unexpected-cfgs
+    ("clippy::wrong_pub_self_convention", "`clippy::wrong_self_convention` now covers this case via the `avoid-breaking-exported-api` config"),
+    // end deprecated lints. used by `cargo dev deprecate_lint`
+]}
+
+#[rustfmt::skip]
+declare_with_version! { RENAMED(RENAMED_VERSION): &[(&str, &str)] = &[
+    #[clippy::version = ""]
+    ("clippy::almost_complete_letter_range", "clippy::almost_complete_range"),
+    #[clippy::version = ""]
+    ("clippy::blacklisted_name", "clippy::disallowed_names"),
+    #[clippy::version = ""]
+    ("clippy::block_in_if_condition_expr", "clippy::blocks_in_conditions"),
+    #[clippy::version = ""]
+    ("clippy::block_in_if_condition_stmt", "clippy::blocks_in_conditions"),
+    #[clippy::version = ""]
+    ("clippy::blocks_in_if_conditions", "clippy::blocks_in_conditions"),
+    #[clippy::version = ""]
+    ("clippy::box_vec", "clippy::box_collection"),
+    #[clippy::version = ""]
+    ("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes"),
+    #[clippy::version = ""]
+    ("clippy::cyclomatic_complexity", "clippy::cognitive_complexity"),
+    #[clippy::version = ""]
+    ("clippy::derive_hash_xor_eq", "clippy::derived_hash_with_manual_eq"),
+    #[clippy::version = ""]
+    ("clippy::disallowed_method", "clippy::disallowed_methods"),
+    #[clippy::version = ""]
+    ("clippy::disallowed_type", "clippy::disallowed_types"),
+    #[clippy::version = ""]
+    ("clippy::eval_order_dependence", "clippy::mixed_read_write_in_expression"),
+    #[clippy::version = "1.51.0"]
+    ("clippy::find_map", "clippy::manual_find_map"),
+    #[clippy::version = "1.53.0"]
+    ("clippy::filter_map", "clippy::manual_filter_map"),
+    #[clippy::version = ""]
+    ("clippy::identity_conversion", "clippy::useless_conversion"),
+    #[clippy::version = "pre 1.29.0"]
+    ("clippy::if_let_redundant_pattern_matching", "clippy::redundant_pattern_matching"),
+    #[clippy::version = ""]
+    ("clippy::if_let_some_result", "clippy::match_result_ok"),
+    #[clippy::version = ""]
+    ("clippy::incorrect_clone_impl_on_copy_type", "clippy::non_canonical_clone_impl"),
+    #[clippy::version = ""]
+    ("clippy::incorrect_partial_ord_impl_on_ord_type", "clippy::non_canonical_partial_ord_impl"),
+    #[clippy::version = ""]
+    ("clippy::integer_arithmetic", "clippy::arithmetic_side_effects"),
+    #[clippy::version = ""]
+    ("clippy::logic_bug", "clippy::overly_complex_bool_expr"),
+    #[clippy::version = ""]
+    ("clippy::new_without_default_derive", "clippy::new_without_default"),
+    #[clippy::version = ""]
+    ("clippy::option_and_then_some", "clippy::bind_instead_of_map"),
+    #[clippy::version = ""]
+    ("clippy::option_expect_used", "clippy::expect_used"),
+    #[clippy::version = ""]
+    ("clippy::option_map_unwrap_or", "clippy::map_unwrap_or"),
+    #[clippy::version = ""]
+    ("clippy::option_map_unwrap_or_else", "clippy::map_unwrap_or"),
+    #[clippy::version = ""]
+    ("clippy::option_unwrap_used", "clippy::unwrap_used"),
+    #[clippy::version = ""]
+    ("clippy::overflow_check_conditional", "clippy::panicking_overflow_checks"),
+    #[clippy::version = ""]
+    ("clippy::ref_in_deref", "clippy::needless_borrow"),
+    #[clippy::version = ""]
+    ("clippy::result_expect_used", "clippy::expect_used"),
+    #[clippy::version = ""]
+    ("clippy::result_map_unwrap_or_else", "clippy::map_unwrap_or"),
+    #[clippy::version = ""]
+    ("clippy::result_unwrap_used", "clippy::unwrap_used"),
+    #[clippy::version = ""]
+    ("clippy::single_char_push_str", "clippy::single_char_add_str"),
+    #[clippy::version = ""]
+    ("clippy::stutter", "clippy::module_name_repetitions"),
+    #[clippy::version = ""]
+    ("clippy::thread_local_initializer_can_be_made_const", "clippy::missing_const_for_thread_local"),
+    #[clippy::version = ""]
+    ("clippy::to_string_in_display", "clippy::recursive_format_impl"),
+    #[clippy::version = ""]
+    ("clippy::unwrap_or_else_default", "clippy::unwrap_or_default"),
+    #[clippy::version = ""]
+    ("clippy::zero_width_space", "clippy::invisible_characters"),
+    #[clippy::version = ""]
+    ("clippy::cast_ref_to_mut", "invalid_reference_casting"),
+    #[clippy::version = ""]
+    ("clippy::clone_double_ref", "suspicious_double_ref_op"),
+    #[clippy::version = ""]
+    ("clippy::cmp_nan", "invalid_nan_comparisons"),
+    #[clippy::version = ""]
+    ("clippy::drop_bounds", "drop_bounds"),
+    #[clippy::version = ""]
+    ("clippy::drop_copy", "dropping_copy_types"),
+    #[clippy::version = ""]
+    ("clippy::drop_ref", "dropping_references"),
+    #[clippy::version = ""]
+    ("clippy::fn_null_check", "useless_ptr_null_checks"),
+    #[clippy::version = ""]
+    ("clippy::for_loop_over_option", "for_loops_over_fallibles"),
+    #[clippy::version = ""]
+    ("clippy::for_loop_over_result", "for_loops_over_fallibles"),
+    #[clippy::version = ""]
+    ("clippy::for_loops_over_fallibles", "for_loops_over_fallibles"),
+    #[clippy::version = ""]
+    ("clippy::forget_copy", "forgetting_copy_types"),
+    #[clippy::version = ""]
+    ("clippy::forget_ref", "forgetting_references"),
+    #[clippy::version = ""]
+    ("clippy::into_iter_on_array", "array_into_iter"),
+    #[clippy::version = ""]
+    ("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"),
+    #[clippy::version = ""]
+    ("clippy::invalid_ref", "invalid_value"),
+    #[clippy::version = ""]
+    ("clippy::invalid_utf8_in_unchecked", "invalid_from_utf8_unchecked"),
+    #[clippy::version = ""]
+    ("clippy::let_underscore_drop", "let_underscore_drop"),
     #[clippy::version = "1.80.0"]
-    pub MAYBE_MISUSED_CFG,
-    "this lint has been replaced by `unexpected_cfgs`"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// This lint has been superseded by rustc's own [`unexpected_cfgs`] lint that is able to detect invalid `#[cfg(linux)]` attributes.
-    ///
-    /// [`unexpected_cfgs`]: https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#unexpected-cfgs
+    ("clippy::maybe_misused_cfg", "unexpected_cfgs"),
+    #[clippy::version = ""]
+    ("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums"),
     #[clippy::version = "1.80.0"]
-    pub MISMATCHED_TARGET_OS,
-    "this lint has been replaced by `unexpected_cfgs`"
-}
+    ("clippy::mismatched_target_os", "unexpected_cfgs"),
+    #[clippy::version = ""]
+    ("clippy::panic_params", "non_fmt_panics"),
+    #[clippy::version = ""]
+    ("clippy::positional_named_format_parameters", "named_arguments_used_positionally"),
+    #[clippy::version = ""]
+    ("clippy::temporary_cstring_as_ptr", "temporary_cstring_as_ptr"),
+    #[clippy::version = ""]
+    ("clippy::undropped_manually_drops", "undropped_manually_drops"),
+    #[clippy::version = ""]
+    ("clippy::unknown_clippy_lints", "unknown_lints"),
+    #[clippy::version = ""]
+    ("clippy::unused_label", "unused_labels"),
+    #[clippy::version = ""]
+    ("clippy::vtable_address_comparisons", "ambiguous_wide_pointer_comparisons"),
+    #[clippy::version = ""]
+    ("clippy::reverse_range_loop", "clippy::reversed_empty_ranges"),
+    // end renamed lints. used by `cargo dev rename_lint`
+]}
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 253f9959e13..d0cb2488468 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
 use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 use clippy_utils::sugg::has_enclosing_paren;
-use clippy_utils::ty::{implements_trait, is_manually_drop, peel_mid_ty_refs};
+use clippy_utils::ty::{implements_trait, is_manually_drop};
 use clippy_utils::{
     expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, peel_middle_ty_refs, DefinedTy,
     ExprUseNode,
@@ -947,7 +947,7 @@ fn report<'tcx>(
             let (expr_str, _expr_is_macro_call) =
                 snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app);
             let ty = typeck.expr_ty(expr);
-            let (_, ref_count) = peel_mid_ty_refs(ty);
+            let (_, ref_count) = peel_middle_ty_refs(ty);
             let deref_str = if ty_changed_count >= ref_count && ref_count != 0 {
                 // a deref call changing &T -> &U requires two deref operators the first time
                 // this occurs. One to remove the reference, a second to call the deref impl.
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index 5b6a5b08aa9..d7b3a7c74f3 100644
--- a/src/tools/clippy/clippy_lints/src/doc/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -5,7 +5,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::macros::{is_panic, root_macro_call_first_node};
 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 clippy_utils::{is_entrypoint_fn, is_trait_impl_item, method_chain_args};
 use pulldown_cmark::Event::{
     Code, DisplayMath, End, FootnoteReference, HardBreak, Html, InlineHtml, InlineMath, Rule, SoftBreak, Start,
     TaskListMarker, Text,
@@ -768,7 +768,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                     );
                 }
             },
-            FootnoteReference(text) | Text(text) => {
+            Text(text) => {
                 paragraph_range.end = range.end;
                 let range_ = range.clone();
                 ticks_unbalanced |= text.contains('`')
@@ -812,7 +812,8 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                     }
                     text_to_check.push((text, range, code_level));
                 }
-            },
+            }
+            FootnoteReference(_) => {}
         }
     }
     headers
@@ -857,7 +858,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
                     "assert" | "assert_eq" | "assert_ne"
                 )
             {
-                self.is_const = in_constant(self.cx, expr.hir_id);
+                self.is_const = self.cx.tcx.hir().is_inside_const_context(expr.hir_id);
                 self.panic_span = Some(macro_call.span);
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
index 4a6ffcd9a78..c7dd7292a14 100644
--- a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_note;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_must_use_func_call;
 use clippy_utils::ty::{is_copy, is_must_use_ty, is_type_lang_item};
 use rustc_hir::{Arm, Expr, ExprKind, LangItem, Node};
@@ -126,14 +126,14 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
                 },
                 _ => return,
             };
-            span_lint_and_note(
-                cx,
-                lint,
-                expr.span,
-                msg,
-                note_span,
-                format!("argument has type `{arg_ty}`"),
-            );
+            span_lint_and_then(cx, lint, expr.span, msg, |diag| {
+                let note = format!("argument has type `{arg_ty}`");
+                if let Some(span) = note_span {
+                    diag.span_note(span, note);
+                } else {
+                    diag.note(note);
+                }
+            });
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/else_if_without_else.rs b/src/tools/clippy/clippy_lints/src/else_if_without_else.rs
index 7a6dc469727..02f9c2c3648 100644
--- a/src/tools/clippy/clippy_lints/src/else_if_without_else.rs
+++ b/src/tools/clippy/clippy_lints/src/else_if_without_else.rs
@@ -1,6 +1,6 @@
 //! Lint on if expressions with an else if, but without a final else branch.
 
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_ast::ast::{Expr, ExprKind};
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
@@ -54,13 +54,15 @@ impl EarlyLintPass for ElseIfWithoutElse {
             && let ExprKind::If(_, _, None) = els.kind
             && !in_external_macro(cx.sess(), item.span)
         {
-            span_lint_and_help(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 ELSE_IF_WITHOUT_ELSE,
                 els.span,
                 "`if` expression with an `else if`, but without a final `else`",
-                None,
-                "add an `else` block here",
+                |diag| {
+                    diag.help("add an `else` block here");
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/empty_drop.rs b/src/tools/clippy/clippy_lints/src/empty_drop.rs
index c5fc72b5e2d..b66dd2108fc 100644
--- a/src/tools/clippy/clippy_lints/src/empty_drop.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_drop.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::peel_blocks;
 use rustc_errors::Applicability;
 use rustc_hir::{Body, ExprKind, Impl, ImplItemKind, Item, ItemKind, Node};
@@ -50,15 +50,14 @@ impl LateLintPass<'_> for EmptyDrop {
             && block.stmts.is_empty()
             && block.expr.is_none()
         {
-            span_lint_and_sugg(
-                cx,
-                EMPTY_DROP,
-                item.span,
-                "empty drop implementation",
-                "try removing this impl",
-                String::new(),
-                Applicability::MaybeIncorrect,
-            );
+            span_lint_and_then(cx, EMPTY_DROP, item.span, "empty drop implementation", |diag| {
+                diag.span_suggestion_hidden(
+                    item.span,
+                    "try removing this impl",
+                    String::new(),
+                    Applicability::MaybeIncorrect,
+                );
+            });
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/endian_bytes.rs b/src/tools/clippy/clippy_lints/src/endian_bytes.rs
index 5bba9c562b9..209104c5385 100644
--- a/src/tools/clippy/clippy_lints/src/endian_bytes.rs
+++ b/src/tools/clippy/clippy_lints/src/endian_bytes.rs
@@ -7,7 +7,6 @@ use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::Ty;
 use rustc_session::declare_lint_pass;
 use rustc_span::Symbol;
-use std::borrow::Cow;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -141,52 +140,6 @@ fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix
         _ => return,
     };
 
-    let mut help = None;
-
-    'build_help: {
-        // all lints disallowed, don't give help here
-        if [&[lint], other_lints.as_slice()]
-            .concat()
-            .iter()
-            .all(|lint| !lint.allowed(cx, expr))
-        {
-            break 'build_help;
-        }
-
-        // ne_bytes and all other lints allowed
-        if lint.as_name(prefix) == ne && other_lints.iter().all(|lint| lint.allowed(cx, expr)) {
-            help = Some(Cow::Borrowed("specify the desired endianness explicitly"));
-            break 'build_help;
-        }
-
-        // le_bytes where ne_bytes allowed but be_bytes is not, or le_bytes where ne_bytes allowed but
-        // le_bytes is not
-        if (lint.as_name(prefix) == le || lint.as_name(prefix) == be) && LintKind::Host.allowed(cx, expr) {
-            help = Some(Cow::Borrowed("use the native endianness instead"));
-            break 'build_help;
-        }
-
-        let allowed_lints = other_lints.iter().filter(|lint| lint.allowed(cx, expr));
-        let len = allowed_lints.clone().count();
-
-        let mut help_str = "use ".to_owned();
-
-        for (i, lint) in allowed_lints.enumerate() {
-            let only_one = len == 1;
-            if !only_one {
-                help_str.push_str("either of ");
-            }
-
-            help_str.push_str(&format!("`{ty}::{}` ", lint.as_name(prefix)));
-
-            if i != len && !only_one {
-                help_str.push_str("or ");
-            }
-        }
-
-        help = Some(Cow::Owned(help_str + "instead"));
-    }
-
     span_lint_and_then(
         cx,
         lint.as_lint(),
@@ -198,9 +151,47 @@ fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix
             if prefix == Prefix::To { " method" } else { "" },
         ),
         move |diag| {
-            if let Some(help) = help {
-                diag.help(help);
+            // all lints disallowed, don't give help here
+            if [&[lint], other_lints.as_slice()]
+                .concat()
+                .iter()
+                .all(|lint| !lint.allowed(cx, expr))
+            {
+                return;
+            }
+
+            // ne_bytes and all other lints allowed
+            if lint.as_name(prefix) == ne && other_lints.iter().all(|lint| lint.allowed(cx, expr)) {
+                diag.help("specify the desired endianness explicitly");
+                return;
+            }
+
+            // le_bytes where ne_bytes allowed but be_bytes is not, or le_bytes where ne_bytes allowed but
+            // le_bytes is not
+            if (lint.as_name(prefix) == le || lint.as_name(prefix) == be) && LintKind::Host.allowed(cx, expr) {
+                diag.help("use the native endianness instead");
+                return;
+            }
+
+            let allowed_lints = other_lints.iter().filter(|lint| lint.allowed(cx, expr));
+            let len = allowed_lints.clone().count();
+
+            let mut help_str = "use ".to_owned();
+
+            for (i, lint) in allowed_lints.enumerate() {
+                let only_one = len == 1;
+                if !only_one {
+                    help_str.push_str("either of ");
+                }
+
+                help_str.push_str(&format!("`{ty}::{}` ", lint.as_name(prefix)));
+
+                if i != len && !only_one {
+                    help_str.push_str("or ");
+                }
             }
+            help_str.push_str("instead");
+            diag.help(help_str);
         },
     );
 }
diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs
index 30eb643c42e..e54cd248ead 100644
--- a/src/tools/clippy/clippy_lints/src/enum_clike.rs
+++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs
@@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
                         .const_eval_poly(def_id.to_def_id())
                         .ok()
                         .map(|val| rustc_middle::mir::Const::from_value(val, ty));
-                    if let Some(Constant::Int(val)) = constant.and_then(|c| mir_to_const(cx, c)) {
+                    if let Some(Constant::Int(val)) = constant.and_then(|c| mir_to_const(cx.tcx, c)) {
                         if let ty::Adt(adt, _) = ty.kind() {
                             if adt.is_enum() {
                                 ty = adt.repr().discr_type().to_ty(cx.tcx);
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 0ed7859418b..5a7226d590c 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -9,8 +9,7 @@ use rustc_hir::{BindingMode, Expr, ExprKind, FnRetTy, Param, PatKind, QPath, Saf
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{
-    self, Binder, ClosureArgs, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, RegionKind, Ty, TyCtxt,
-    TypeVisitableExt, TypeckResults,
+    self, Binder, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, Ty, TypeVisitableExt, TypeckResults,
 };
 use rustc_session::declare_lint_pass;
 use rustc_span::symbol::sym;
@@ -74,159 +73,184 @@ declare_clippy_lint! {
 declare_lint_pass!(EtaReduction => [REDUNDANT_CLOSURE, REDUNDANT_CLOSURE_FOR_METHOD_CALLS]);
 
 impl<'tcx> LateLintPass<'tcx> for EtaReduction {
-    #[allow(clippy::too_many_lines)]
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        let body = if let ExprKind::Closure(c) = expr.kind
-            && c.fn_decl.inputs.iter().all(|ty| matches!(ty.kind, TyKind::Infer))
-            && matches!(c.fn_decl.output, FnRetTy::DefaultReturn(_))
-            && !expr.span.from_expansion()
-        {
-            cx.tcx.hir().body(c.body)
-        } else {
-            return;
-        };
-
-        if body.value.span.from_expansion() {
-            if body.params.is_empty() {
-                if let Some(VecArgs::Vec(&[])) = VecArgs::hir(cx, body.value) {
-                    // replace `|| vec![]` with `Vec::new`
-                    span_lint_and_sugg(
-                        cx,
-                        REDUNDANT_CLOSURE,
-                        expr.span,
-                        "redundant closure",
-                        "replace the closure with `Vec::new`",
-                        "std::vec::Vec::new".into(),
-                        Applicability::MachineApplicable,
-                    );
-                }
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
+        if let ExprKind::MethodCall(_method, receiver, args, _) = expr.kind {
+            for arg in args {
+                check_clousure(cx, Some(receiver), arg);
             }
-            // skip `foo(|| macro!())`
-            return;
         }
+        if let ExprKind::Call(func, args) = expr.kind {
+            check_clousure(cx, None, func);
+            for arg in args {
+                check_clousure(cx, None, arg);
+            }
+        }
+    }
+}
 
-        let typeck = cx.typeck_results();
-        let closure = if let ty::Closure(_, closure_subs) = typeck.expr_ty(expr).kind() {
-            closure_subs.as_closure()
-        } else {
-            return;
-        };
+#[allow(clippy::too_many_lines)]
+fn check_clousure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx>>, expr: &Expr<'tcx>) {
+    let body = if let ExprKind::Closure(c) = expr.kind
+        && c.fn_decl.inputs.iter().all(|ty| matches!(ty.kind, TyKind::Infer))
+        && matches!(c.fn_decl.output, FnRetTy::DefaultReturn(_))
+        && !expr.span.from_expansion()
+    {
+        cx.tcx.hir().body(c.body)
+    } else {
+        return;
+    };
 
-        if is_adjusted(cx, body.value) {
-            return;
+    if body.value.span.from_expansion() {
+        if body.params.is_empty() {
+            if let Some(VecArgs::Vec(&[])) = VecArgs::hir(cx, body.value) {
+                // replace `|| vec![]` with `Vec::new`
+                span_lint_and_sugg(
+                    cx,
+                    REDUNDANT_CLOSURE,
+                    expr.span,
+                    "redundant closure",
+                    "replace the closure with `Vec::new`",
+                    "std::vec::Vec::new".into(),
+                    Applicability::MachineApplicable,
+                );
+            }
         }
+        // skip `foo(|| macro!())`
+        return;
+    }
 
-        match body.value.kind {
-            ExprKind::Call(callee, args)
-                if matches!(
-                    callee.kind,
-                    ExprKind::Path(QPath::Resolved(..) | QPath::TypeRelative(..))
-                ) =>
+    if is_adjusted(cx, body.value) {
+        return;
+    }
+
+    let typeck = cx.typeck_results();
+    let closure = if let ty::Closure(_, closure_subs) = typeck.expr_ty(expr).kind() {
+        closure_subs.as_closure()
+    } else {
+        return;
+    };
+    let closure_sig = cx.tcx.signature_unclosure(closure.sig(), Safety::Safe).skip_binder();
+    match body.value.kind {
+        ExprKind::Call(callee, args)
+            if matches!(
+                callee.kind,
+                ExprKind::Path(QPath::Resolved(..) | QPath::TypeRelative(..))
+            ) =>
+        {
+            let callee_ty_raw = typeck.expr_ty(callee);
+            let callee_ty = callee_ty_raw.peel_refs();
+            if matches!(type_diagnostic_name(cx, callee_ty), Some(sym::Arc | sym::Rc))
+                || !check_inputs(typeck, body.params, None, args)
             {
-                let callee_ty_raw = typeck.expr_ty(callee);
-                let callee_ty = callee_ty_raw.peel_refs();
-                if matches!(type_diagnostic_name(cx, callee_ty), Some(sym::Arc | sym::Rc))
-                    || !check_inputs(typeck, body.params, None, args)
-                {
-                    return;
-                }
-                let callee_ty_adjusted = typeck
-                    .expr_adjustments(callee)
-                    .last()
-                    .map_or(callee_ty, |a| a.target.peel_refs());
+                return;
+            }
+            let callee_ty_adjusted = typeck
+                .expr_adjustments(callee)
+                .last()
+                .map_or(callee_ty, |a| a.target.peel_refs());
 
-                let sig = match callee_ty_adjusted.kind() {
-                    ty::FnDef(def, _) => {
-                        // Rewriting `x(|| f())` to `x(f)` where f is marked `#[track_caller]` moves the `Location`
-                        if cx.tcx.has_attr(*def, sym::track_caller) {
-                            return;
-                        }
+            let sig = match callee_ty_adjusted.kind() {
+                ty::FnDef(def, _) => {
+                    // Rewriting `x(|| f())` to `x(f)` where f is marked `#[track_caller]` moves the `Location`
+                    if cx.tcx.has_attr(*def, sym::track_caller) {
+                        return;
+                    }
 
-                        cx.tcx.fn_sig(def).skip_binder().skip_binder()
-                    },
-                    ty::FnPtr(sig) => sig.skip_binder(),
-                    ty::Closure(_, subs) => cx
-                        .tcx
-                        .signature_unclosure(subs.as_closure().sig(), Safety::Safe)
-                        .skip_binder(),
-                    _ => {
-                        if typeck.type_dependent_def_id(body.value.hir_id).is_some()
-                            && let subs = typeck.node_args(body.value.hir_id)
-                            && let output = typeck.expr_ty(body.value)
-                            && let ty::Tuple(tys) = *subs.type_at(1).kind()
-                        {
-                            cx.tcx.mk_fn_sig(tys, output, false, Safety::Safe, Abi::Rust)
-                        } else {
-                            return;
-                        }
-                    },
-                };
-                if check_sig(cx, closure, sig)
-                    && let generic_args = typeck.node_args(callee.hir_id)
-                    // Given some trait fn `fn f() -> ()` and some type `T: Trait`, `T::f` is not
-                    // `'static` unless `T: 'static`. The cast `T::f as fn()` will, however, result
-                    // in a type which is `'static`.
-                    // For now ignore all callee types which reference a type parameter.
-                    && !generic_args.types().any(|t| matches!(t.kind(), ty::Param(_)))
-                {
-                    span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| {
-                        if let Some(mut snippet) = snippet_opt(cx, callee.span) {
-                            if path_to_local(callee).map_or(false, |l| {
-                                // FIXME: Do we really need this `local_used_in` check?
-                                // Isn't it checking something like... `callee(callee)`?
-                                // If somehow this check is needed, add some test for it,
-                                // 'cuz currently nothing changes after deleting this check.
-                                local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr)
-                            }) {
-                                match cx.tcx.infer_ctxt().build().err_ctxt().type_implements_fn_trait(
-                                    cx.param_env,
-                                    Binder::bind_with_vars(callee_ty_adjusted, List::empty()),
-                                    ty::PredicatePolarity::Positive,
-                                ) {
-                                    // Mutable closure is used after current expr; we cannot consume it.
-                                    Ok((ClosureKind::FnMut, _)) => snippet = format!("&mut {snippet}"),
-                                    Ok((ClosureKind::Fn, _)) if !callee_ty_raw.is_ref() => {
-                                        snippet = format!("&{snippet}");
-                                    },
-                                    _ => (),
-                                }
+                    cx.tcx.fn_sig(def).skip_binder().skip_binder()
+                },
+                ty::FnPtr(sig) => sig.skip_binder(),
+                ty::Closure(_, subs) => cx
+                    .tcx
+                    .signature_unclosure(subs.as_closure().sig(), Safety::Safe)
+                    .skip_binder(),
+                _ => {
+                    if typeck.type_dependent_def_id(body.value.hir_id).is_some()
+                        && let subs = typeck.node_args(body.value.hir_id)
+                        && let output = typeck.expr_ty(body.value)
+                        && let ty::Tuple(tys) = *subs.type_at(1).kind()
+                    {
+                        cx.tcx.mk_fn_sig(tys, output, false, Safety::Safe, Abi::Rust)
+                    } else {
+                        return;
+                    }
+                },
+            };
+            if let Some(outer) = outer_receiver
+                && ty_has_static(sig.output())
+                && let generic_args = typeck.node_args(outer.hir_id)
+                // HACK: Given a closure in `T.method(|| f())`, where `fn f() -> U where U: 'static`, `T.method(f)`
+                // will succeed iff `T: 'static`. But the region of `T` is always erased by `typeck.expr_ty()` when
+                // T is a generic type. For example, return type of `Option<String>::as_deref()` is a generic.
+                // So we have a hack like this.
+                && generic_args.len() > 0
+            {
+                return;
+            }
+            if check_sig(closure_sig, sig)
+                && let generic_args = typeck.node_args(callee.hir_id)
+                // Given some trait fn `fn f() -> ()` and some type `T: Trait`, `T::f` is not
+                // `'static` unless `T: 'static`. The cast `T::f as fn()` will, however, result
+                // in a type which is `'static`.
+                // For now ignore all callee types which reference a type parameter.
+                && !generic_args.types().any(|t| matches!(t.kind(), ty::Param(_)))
+            {
+                span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| {
+                    if let Some(mut snippet) = snippet_opt(cx, callee.span) {
+                        if path_to_local(callee).map_or(false, |l| {
+                            // FIXME: Do we really need this `local_used_in` check?
+                            // Isn't it checking something like... `callee(callee)`?
+                            // If somehow this check is needed, add some test for it,
+                            // 'cuz currently nothing changes after deleting this check.
+                            local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr)
+                        }) {
+                            match cx.tcx.infer_ctxt().build().err_ctxt().type_implements_fn_trait(
+                                cx.param_env,
+                                Binder::bind_with_vars(callee_ty_adjusted, List::empty()),
+                                ty::PredicatePolarity::Positive,
+                            ) {
+                                // Mutable closure is used after current expr; we cannot consume it.
+                                Ok((ClosureKind::FnMut, _)) => snippet = format!("&mut {snippet}"),
+                                Ok((ClosureKind::Fn, _)) if !callee_ty_raw.is_ref() => {
+                                    snippet = format!("&{snippet}");
+                                },
+                                _ => (),
                             }
-                            diag.span_suggestion(
-                                expr.span,
-                                "replace the closure with the function itself",
-                                snippet,
-                                Applicability::MachineApplicable,
-                            );
                         }
-                    });
-                }
-            },
-            ExprKind::MethodCall(path, self_, args, _) if check_inputs(typeck, body.params, Some(self_), args) => {
-                if let Some(method_def_id) = typeck.type_dependent_def_id(body.value.hir_id)
-                    && !cx.tcx.has_attr(method_def_id, sym::track_caller)
-                    && check_sig(cx, closure, cx.tcx.fn_sig(method_def_id).skip_binder().skip_binder())
-                {
-                    span_lint_and_then(
-                        cx,
-                        REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
-                        expr.span,
-                        "redundant closure",
-                        |diag| {
-                            let args = typeck.node_args(body.value.hir_id);
-                            let caller = self_.hir_id.owner.def_id;
-                            let type_name = get_path_from_caller_to_method_type(cx.tcx, caller, method_def_id, args);
-                            diag.span_suggestion(
-                                expr.span,
-                                "replace the closure with the method itself",
-                                format!("{}::{}", type_name, path.ident.name),
-                                Applicability::MachineApplicable,
-                            );
-                        },
-                    );
-                }
-            },
-            _ => (),
-        }
+                        diag.span_suggestion(
+                            expr.span,
+                            "replace the closure with the function itself",
+                            snippet,
+                            Applicability::MachineApplicable,
+                        );
+                    }
+                });
+            }
+        },
+        ExprKind::MethodCall(path, self_, args, _) if check_inputs(typeck, body.params, Some(self_), args) => {
+            if let Some(method_def_id) = typeck.type_dependent_def_id(body.value.hir_id)
+                && !cx.tcx.has_attr(method_def_id, sym::track_caller)
+                && check_sig(closure_sig, cx.tcx.fn_sig(method_def_id).skip_binder().skip_binder())
+            {
+                span_lint_and_then(
+                    cx,
+                    REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
+                    expr.span,
+                    "redundant closure",
+                    |diag| {
+                        let args = typeck.node_args(body.value.hir_id);
+                        let caller = self_.hir_id.owner.def_id;
+                        let type_name = get_path_from_caller_to_method_type(cx.tcx, caller, method_def_id, args);
+                        diag.span_suggestion(
+                            expr.span,
+                            "replace the closure with the method itself",
+                            format!("{}::{}", type_name, path.ident.name),
+                            Applicability::MachineApplicable,
+                        );
+                    },
+                );
+            }
+        },
+        _ => (),
     }
 }
 
@@ -251,12 +275,8 @@ fn check_inputs(
         })
 }
 
-fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure: ClosureArgs<TyCtxt<'tcx>>, call_sig: FnSig<'_>) -> bool {
-    call_sig.safety == Safety::Safe
-        && !has_late_bound_to_non_late_bound_regions(
-            cx.tcx.signature_unclosure(closure.sig(), Safety::Safe).skip_binder(),
-            call_sig,
-        )
+fn check_sig<'tcx>(closure_sig: FnSig<'tcx>, call_sig: FnSig<'tcx>) -> bool {
+    call_sig.safety == Safety::Safe && !has_late_bound_to_non_late_bound_regions(closure_sig, call_sig)
 }
 
 /// This walks through both signatures and checks for any time a late-bound region is expected by an
@@ -265,7 +285,7 @@ fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure: ClosureArgs<TyCtxt<'tcx>>, c
 /// This is needed because rustc is unable to late bind early-bound regions in a function signature.
 fn has_late_bound_to_non_late_bound_regions(from_sig: FnSig<'_>, to_sig: FnSig<'_>) -> bool {
     fn check_region(from_region: Region<'_>, to_region: Region<'_>) -> bool {
-        matches!(from_region.kind(), RegionKind::ReBound(..)) && !matches!(to_region.kind(), RegionKind::ReBound(..))
+        from_region.is_bound() && !to_region.is_bound()
     }
 
     fn check_subs(from_subs: &[GenericArg<'_>], to_subs: &[GenericArg<'_>]) -> bool {
@@ -318,3 +338,8 @@ fn has_late_bound_to_non_late_bound_regions(from_sig: FnSig<'_>, to_sig: FnSig<'
         .zip(to_sig.inputs_and_output)
         .any(|(from_ty, to_ty)| check_ty(from_ty, to_ty))
 }
+
+fn ty_has_static(ty: Ty<'_>) -> bool {
+    ty.walk()
+        .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(re) if re.is_static()))
+}
diff --git a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
index 0f4176ec73b..9bf3baba4b5 100644
--- a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
+++ b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
@@ -88,11 +88,11 @@ impl LateLintPass<'_> for ExhaustiveItems {
             && !attrs.iter().any(|a| a.has_name(sym::non_exhaustive))
             && fields.iter().all(|f| cx.tcx.visibility(f.def_id).is_public())
         {
-            let suggestion_span = item.span.shrink_to_lo();
-            let indent = " ".repeat(indent_of(cx, item.span).unwrap_or(0));
             span_lint_and_then(cx, lint, item.span, msg, |diag| {
+                let suggestion_span = item.span.shrink_to_lo();
+                let indent = " ".repeat(indent_of(cx, item.span).unwrap_or(0));
                 let sugg = format!("#[non_exhaustive]\n{indent}");
-                diag.span_suggestion(
+                diag.span_suggestion_verbose(
                     suggestion_span,
                     "try adding #[non_exhaustive]",
                     sugg,
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
index bb74e345703..95b8e882da7 100644
--- a/src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs
+++ b/src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_ast::ast::{Item, ItemKind, VisibilityKind};
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::declare_lint_pass;
@@ -62,13 +62,15 @@ impl EarlyLintPass for FieldScopedVisibilityModifiers {
                 // pub(self) is equivalent to not using pub at all, so we ignore it
                 continue;
             }
-            span_lint_and_help(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 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",
+                |diag| {
+                    diag.help("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 6adcd2235dc..f095c1add91 100644
--- a/src/tools/clippy/clippy_lints/src/float_literal.rs
+++ b/src/tools/clippy/clippy_lints/src/float_literal.rs
@@ -1,7 +1,7 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::numeric_literal;
 use rustc_ast::ast::{self, LitFloatType, LitKind};
-use rustc_errors::Applicability;
+use rustc_errors::{Applicability, SuggestionStyle};
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, FloatTy};
@@ -105,32 +105,43 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
             if is_whole && !sym_str.contains(['e', 'E']) {
                 // Normalize the literal by stripping the fractional portion
                 if sym_str.split('.').next().unwrap() != float_str {
-                    // If the type suffix is missing the suggestion would be
-                    // incorrectly interpreted as an integer so adding a `.0`
-                    // suffix to prevent that.
-                    if type_suffix.is_none() {
-                        float_str.push_str(".0");
-                    }
-
-                    span_lint_and_sugg(
+                    span_lint_and_then(
                         cx,
                         LOSSY_FLOAT_LITERAL,
                         expr.span,
                         "literal cannot be represented as the underlying type without loss of precision",
-                        "consider changing the type or replacing it with",
-                        numeric_literal::format(&float_str, type_suffix, true),
-                        Applicability::MachineApplicable,
+                        |diag| {
+                            // If the type suffix is missing the suggestion would be
+                            // incorrectly interpreted as an integer so adding a `.0`
+                            // suffix to prevent that.
+                            if type_suffix.is_none() {
+                                float_str.push_str(".0");
+                            }
+                            diag.span_suggestion_with_style(
+                                expr.span,
+                                "consider changing the type or replacing it with",
+                                numeric_literal::format(&float_str, type_suffix, true),
+                                Applicability::MachineApplicable,
+                                SuggestionStyle::ShowAlways,
+                            );
+                        },
                     );
                 }
             } else if digits > max as usize && float_str.len() < sym_str.len() {
-                span_lint_and_sugg(
+                span_lint_and_then(
                     cx,
                     EXCESSIVE_PRECISION,
                     expr.span,
                     "float has excessive precision",
-                    "consider changing the type or truncating it to",
-                    numeric_literal::format(&float_str, type_suffix, true),
-                    Applicability::MachineApplicable,
+                    |diag| {
+                        diag.span_suggestion_with_style(
+                            expr.span,
+                            "consider changing the type or truncating it to",
+                            numeric_literal::format(&float_str, type_suffix, true),
+                            Applicability::MachineApplicable,
+                            SuggestionStyle::ShowAlways,
+                        );
+                    },
                 );
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
index 68bdf88d0a7..bf4bcabfe89 100644
--- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
@@ -1,9 +1,9 @@
 use clippy_utils::consts::Constant::{Int, F32, F64};
-use clippy_utils::consts::{constant, constant_simple, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::{
-    eq_expr_value, get_parent_expr, higher, in_constant, is_inherent_method_call, is_no_std_crate, numeric_literal,
-    peel_blocks, sugg,
+    eq_expr_value, get_parent_expr, higher, is_in_const_context, is_inherent_method_call, is_no_std_crate,
+    numeric_literal, peel_blocks, sugg,
 };
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp};
@@ -112,7 +112,7 @@ declare_lint_pass!(FloatingPointArithmetic => [
 // Returns the specialized log method for a given base if base is constant
 // and is one of 2, 10 and e
 fn get_specialized_log_method(cx: &LateContext<'_>, base: &Expr<'_>) -> Option<&'static str> {
-    if let Some(value) = constant(cx, cx.typeck_results(), base) {
+    if let Some(value) = ConstEvalCtxt::new(cx).eval(base) {
         if F32(2.0) == value || F64(2.0) == value {
             return Some("log2");
         } else if F32(10.0) == value || F64(10.0) == value {
@@ -182,10 +182,8 @@ fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) {
         rhs,
     ) = receiver.kind
     {
-        let recv = match (
-            constant(cx, cx.typeck_results(), lhs),
-            constant(cx, cx.typeck_results(), rhs),
-        ) {
+        let ecx = ConstEvalCtxt::new(cx);
+        let recv = match (ecx.eval(lhs), ecx.eval(rhs)) {
             (Some(value), _) if F32(1.0) == value || F64(1.0) == value => rhs,
             (_, Some(value)) if F32(1.0) == value || F64(1.0) == value => lhs,
             _ => return,
@@ -230,7 +228,7 @@ fn get_integer_from_float_constant(value: &Constant<'_>) -> Option<i32> {
 
 fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
     // Check receiver
-    if let Some(value) = constant(cx, cx.typeck_results(), receiver) {
+    if let Some(value) = ConstEvalCtxt::new(cx).eval(receiver) {
         if let Some(method) = if F32(f32_consts::E) == value || F64(f64_consts::E) == value {
             Some("exp")
         } else if F32(2.0) == value || F64(2.0) == value {
@@ -251,7 +249,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args:
     }
 
     // Check argument
-    if let Some(value) = constant(cx, cx.typeck_results(), &args[0]) {
+    if let Some(value) = ConstEvalCtxt::new(cx).eval(&args[0]) {
         let (lint, help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value {
             (
                 SUBOPTIMAL_FLOPS,
@@ -291,7 +289,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args:
 }
 
 fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
-    if let Some(value) = constant(cx, cx.typeck_results(), &args[0]) {
+    if let Some(value) = ConstEvalCtxt::new(cx).eval(&args[0]) {
         if value == Int(2) {
             if let Some(parent) = get_parent_expr(cx, expr) {
                 if let Some(grandparent) = get_parent_expr(cx, parent) {
@@ -397,8 +395,9 @@ fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option<String> {
             ) = &add_rhs.kind
             && lmethod_name.as_str() == "powi"
             && rmethod_name.as_str() == "powi"
-            && let Some(lvalue) = constant(cx, cx.typeck_results(), largs_1)
-            && let Some(rvalue) = constant(cx, cx.typeck_results(), rargs_1)
+            && let ecx = ConstEvalCtxt::new(cx)
+            && let Some(lvalue) = ecx.eval(largs_1)
+            && let Some(rvalue) = ecx.eval(rargs_1)
             && Int(2) == lvalue
             && Int(2) == rvalue
         {
@@ -438,7 +437,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) {
         rhs,
     ) = expr.kind
         && cx.typeck_results().expr_ty(lhs).is_floating_point()
-        && let Some(value) = constant(cx, cx.typeck_results(), rhs)
+        && let Some(value) = ConstEvalCtxt::new(cx).eval(rhs)
         && (F32(1.0) == value || F64(1.0) == value)
         && let ExprKind::MethodCall(path, self_arg, ..) = &lhs.kind
         && cx.typeck_results().expr_ty(self_arg).is_floating_point()
@@ -552,7 +551,7 @@ fn is_testing_negative(cx: &LateContext<'_>, expr: &Expr<'_>, test: &Expr<'_>) -
 
 /// Returns true iff expr is some zero literal
 fn is_zero(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    match constant_simple(cx, cx.typeck_results(), expr) {
+    match ConstEvalCtxt::new(cx).eval_simple(expr) {
         Some(Int(i)) => i == 0,
         Some(F32(f)) => f == 0.0,
         Some(F64(f)) => f == 0.0,
@@ -696,8 +695,9 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
             mul_lhs,
             mul_rhs,
         ) = &div_lhs.kind
-        && let Some(rvalue) = constant(cx, cx.typeck_results(), div_rhs)
-        && let Some(lvalue) = constant(cx, cx.typeck_results(), mul_rhs)
+        && let ecx = ConstEvalCtxt::new(cx)
+        && let Some(rvalue) = ecx.eval(div_rhs)
+        && let Some(lvalue) = ecx.eval(mul_rhs)
     {
         // TODO: also check for constant values near PI/180 or 180/PI
         if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue)
@@ -753,7 +753,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
 impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         // All of these operations are currently not const and are in std.
-        if in_constant(cx, expr.hir_id) {
+        if is_in_const_context(cx) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/format_push_string.rs b/src/tools/clippy/clippy_lints/src/format_push_string.rs
index a75538dd329..d05c5a01f41 100644
--- a/src/tools/clippy/clippy_lints/src/format_push_string.rs
+++ b/src/tools/clippy/clippy_lints/src/format_push_string.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::ty::is_type_lang_item;
 use clippy_utils::{higher, match_def_path, paths};
 use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem, MatchSource};
@@ -81,13 +81,15 @@ impl<'tcx> LateLintPass<'tcx> for FormatPushString {
             _ => return,
         };
         if is_format(cx, arg) {
-            span_lint_and_help(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 FORMAT_PUSH_STRING,
                 expr.span,
                 "`format!(..)` appended to existing `String`",
-                None,
-                "consider using `write!` to avoid the extra allocation",
+                |diag| {
+                    diag.help("consider using `write!` to avoid the extra allocation");
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
index 9acb72b2e37..6ab7bbc2dfc 100644
--- a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
+++ b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
-use clippy_utils::{in_constant, is_integer_literal};
+use clippy_utils::{is_in_const_context, is_integer_literal};
 use rustc_errors::Applicability;
 use rustc_hir::{def, Expr, ExprKind, LangItem, PrimTy, QPath, TyKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -62,8 +62,8 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 {
             && matches!(prim_ty, PrimTy::Int(_) | PrimTy::Uint(_))
 
             // do not lint in constant context, because the suggestion won't work.
-            // NB: keep this check until a new `const_trait_impl` is available and stablized.
-            && !in_constant(cx, exp.hir_id)
+            // NB: keep this check until a new `const_trait_impl` is available and stabilized.
+            && !is_in_const_context(cx)
         {
             let expr = if let ExprKind::AddrOf(_, _, expr) = &src.kind {
                 let ty = cx.typeck_results().expr_ty(expr);
diff --git a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
index b38cc7b36a1..1c52514a330 100644
--- a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
+++ b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::for_each_expr_without_closures;
-use clippy_utils::{higher, SpanlessEq};
+use clippy_utils::{eq_expr_value, higher};
 use core::ops::ControlFlow;
 use rustc_errors::Diag;
 use rustc_hir::{Expr, ExprKind};
@@ -51,53 +51,45 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex {
             if_else: Some(if_else),
             ..
         }) = higher::IfLet::hir(cx, expr)
+            && let Some(op_mutex) = for_each_expr_without_closures(let_expr, |e| mutex_lock_call(cx, e, None))
+            && let Some(arm_mutex) =
+                for_each_expr_without_closures((if_then, if_else), |e| mutex_lock_call(cx, e, Some(op_mutex)))
         {
-            let is_mutex_lock = |e: &'tcx Expr<'tcx>| {
-                if let Some(mutex) = is_mutex_lock_call(cx, e) {
-                    ControlFlow::Break(mutex)
-                } else {
-                    ControlFlow::Continue(())
-                }
+            let diag = |diag: &mut Diag<'_, ()>| {
+                diag.span_label(
+                    op_mutex.span,
+                    "this Mutex will remain locked for the entire `if let`-block...",
+                );
+                diag.span_label(
+                    arm_mutex.span,
+                    "... and is tried to lock again here, which will always deadlock.",
+                );
+                diag.help("move the lock call outside of the `if let ...` expression");
             };
-
-            let op_mutex = for_each_expr_without_closures(let_expr, is_mutex_lock);
-            if let Some(op_mutex) = op_mutex {
-                let arm_mutex = for_each_expr_without_closures((if_then, if_else), is_mutex_lock);
-                if let Some(arm_mutex) = arm_mutex
-                    && SpanlessEq::new(cx).eq_expr(op_mutex, arm_mutex)
-                {
-                    let diag = |diag: &mut Diag<'_, ()>| {
-                        diag.span_label(
-                            op_mutex.span,
-                            "this Mutex will remain locked for the entire `if let`-block...",
-                        );
-                        diag.span_label(
-                            arm_mutex.span,
-                            "... and is tried to lock again here, which will always deadlock.",
-                        );
-                        diag.help("move the lock call outside of the `if let ...` expression");
-                    };
-                    span_lint_and_then(
-                        cx,
-                        IF_LET_MUTEX,
-                        expr.span,
-                        "calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock",
-                        diag,
-                    );
-                }
-            }
+            span_lint_and_then(
+                cx,
+                IF_LET_MUTEX,
+                expr.span,
+                "calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock",
+                diag,
+            );
         }
     }
 }
 
-fn is_mutex_lock_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
+fn mutex_lock_call<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    op_mutex: Option<&'tcx Expr<'_>>,
+) -> ControlFlow<&'tcx Expr<'tcx>> {
     if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind
         && path.ident.as_str() == "lock"
         && let ty = cx.typeck_results().expr_ty(self_arg).peel_refs()
         && is_type_diagnostic_item(cx, ty, sym::Mutex)
+        && op_mutex.map_or(true, |op| eq_expr_value(cx, self_arg, op))
     {
-        Some(self_arg)
+        ControlFlow::Break(self_arg)
     } else {
-        None
+        ControlFlow::Continue(())
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/if_not_else.rs b/src/tools/clippy/clippy_lints/src/if_not_else.rs
index 2f6daeeb90d..0ebd8d0c237 100644
--- a/src/tools/clippy/clippy_lints/src/if_not_else.rs
+++ b/src/tools/clippy/clippy_lints/src/if_not_else.rs
@@ -1,7 +1,7 @@
 //! lint on if branches that could be swapped so no `!` operation is necessary
 //! on the condition
 
-use clippy_utils::consts::{constant_simple, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::is_else_clause;
 use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
@@ -49,7 +49,7 @@ declare_clippy_lint! {
 declare_lint_pass!(IfNotElse => [IF_NOT_ELSE]);
 
 fn is_zero_const(expr: &Expr<'_>, cx: &LateContext<'_>) -> bool {
-    if let Some(value) = constant_simple(cx, cx.typeck_results(), expr) {
+    if let Some(value) = ConstEvalCtxt::new(cx).eval_simple(expr) {
         return Constant::Int(0) == value;
     }
     false
diff --git a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
index 39ea16b05d1..0bca53c1536 100644
--- a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
+++ b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
@@ -1,10 +1,12 @@
 use clippy_config::msrvs::{self, Msrv};
 use clippy_config::Conf;
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::eager_or_lazy::switch_to_eager_eval;
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{contains_return, higher, in_constant, is_else_clause, is_res_lang_ctor, path_res, peel_blocks};
+use clippy_utils::{
+    contains_return, higher, is_else_clause, is_in_const_context, is_res_lang_ctor, path_res, peel_blocks,
+};
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, OptionSome};
 use rustc_hir::{Expr, ExprKind};
@@ -76,37 +78,44 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
             && is_res_lang_ctor(cx, path_res(cx, then_call), OptionSome)
             && is_res_lang_ctor(cx, path_res(cx, peel_blocks(els)), OptionNone)
             && !is_else_clause(cx.tcx, expr)
-            && !in_constant(cx, expr.hir_id)
+            && !is_in_const_context(cx)
             && !in_external_macro(cx.sess(), expr.span)
             && self.msrv.meets(msrvs::BOOL_THEN)
             && !contains_return(then_block.stmts)
         {
-            let mut app = Applicability::Unspecified;
-            let cond_snip = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "[condition]", &mut app)
-                .maybe_par()
-                .to_string();
-            let arg_snip = snippet_with_context(cx, then_arg.span, ctxt, "[body]", &mut app).0;
-            let mut method_body = if then_block.stmts.is_empty() {
-                arg_snip.into_owned()
-            } else {
-                format!("{{ /* snippet */ {arg_snip} }}")
-            };
             let method_name = if switch_to_eager_eval(cx, expr) && self.msrv.meets(msrvs::BOOL_THEN_SOME) {
                 "then_some"
             } else {
-                method_body.insert_str(0, "|| ");
                 "then"
             };
 
-            let help =
-                format!("consider using `bool::{method_name}` like: `{cond_snip}.{method_name}({method_body})`",);
-            span_lint_and_help(
+            span_lint_and_then(
                 cx,
                 IF_THEN_SOME_ELSE_NONE,
                 expr.span,
                 format!("this could be simplified with `bool::{method_name}`"),
-                None,
-                help,
+                |diag| {
+                    let mut app = Applicability::Unspecified;
+                    let cond_snip = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "[condition]", &mut app)
+                        .maybe_par()
+                        .to_string();
+                    let arg_snip = snippet_with_context(cx, then_arg.span, ctxt, "[body]", &mut app).0;
+                    let method_body = if let Some(first_stmt) = then_block.stmts.first() {
+                        let (block_snippet, _) =
+                            snippet_with_context(cx, first_stmt.span.until(then_arg.span), ctxt, "..", &mut app);
+                        let closure = if method_name == "then" { "|| " } else { "" };
+                        format!("{closure} {{ {block_snippet}; {arg_snip} }}")
+                    } else {
+                        arg_snip.into_owned()
+                    };
+
+                    diag.span_suggestion(
+                        expr.span,
+                        "try",
+                        format!("{cond_snip}.{method_name}({method_body})"),
+                        app,
+                    );
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
index 344a04e6e7e..e56f33f8dcf 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
@@ -1,7 +1,7 @@
 use std::borrow::Cow;
 use std::collections::BTreeMap;
 
-use rustc_errors::Diag;
+use rustc_errors::{Applicability, Diag};
 use rustc_hir as hir;
 use rustc_hir::intravisit::{walk_body, walk_expr, walk_inf, walk_ty, Visitor};
 use rustc_hir::{Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind};
@@ -13,7 +13,7 @@ use rustc_session::declare_lint_pass;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 
-use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::{snippet, IntoSpan, SpanRangeExt};
 use clippy_utils::ty::is_type_diagnostic_item;
 
@@ -77,33 +77,32 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
                 &generics_snip[1..generics_snip.len() - 1]
             };
 
-            multispan_sugg(
-                diag,
-                "consider adding a type parameter",
-                vec![
-                    (
-                        generics_suggestion_span,
-                        format!(
-                            "<{generics_snip}{}S: ::std::hash::BuildHasher{}>",
-                            if generics_snip.is_empty() { "" } else { ", " },
-                            if vis.suggestions.is_empty() {
-                                ""
-                            } else {
-                                // request users to add `Default` bound so that generic constructors can be used
-                                " + Default"
-                            },
-                        ),
-                    ),
-                    (
-                        target.span(),
-                        format!("{}<{}, S>", target.type_name(), target.type_arguments(),),
+            let mut suggestions = vec![
+                (
+                    generics_suggestion_span,
+                    format!(
+                        "<{generics_snip}{}S: ::std::hash::BuildHasher{}>",
+                        if generics_snip.is_empty() { "" } else { ", " },
+                        if vis.suggestions.is_empty() {
+                            ""
+                        } else {
+                            // request users to add `Default` bound so that generic constructors can be used
+                            " + Default"
+                        },
                     ),
-                ],
+                ),
+                (
+                    target.span(),
+                    format!("{}<{}, S>", target.type_name(), target.type_arguments(),),
+                ),
+            ];
+            suggestions.extend(vis.suggestions);
+
+            diag.multipart_suggestion(
+                "add a type parameter for `BuildHasher`",
+                suggestions,
+                Applicability::MaybeIncorrect,
             );
-
-            if !vis.suggestions.is_empty() {
-                multispan_sugg(diag, "...and use generic constructor", vis.suggestions);
-            }
         }
 
         if !cx.effective_visibilities.is_exported(item.owner_id.def_id) {
diff --git a/src/tools/clippy/clippy_lints/src/implicit_return.rs b/src/tools/clippy/clippy_lints/src/implicit_return.rs
index a102b434cfa..b926e1e62ba 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_return.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_return.rs
@@ -3,7 +3,7 @@ use clippy_utils::source::{snippet_with_applicability, snippet_with_context, wal
 use clippy_utils::visitors::for_each_expr_without_closures;
 use clippy_utils::{get_async_fn_body, is_async_fn, is_from_proc_macro};
 use core::ops::ControlFlow;
-use rustc_errors::Applicability;
+use rustc_errors::{Applicability, SuggestionStyle};
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, FnRetTy, HirId};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -45,8 +45,6 @@ declare_clippy_lint! {
 declare_lint_pass!(ImplicitReturn => [IMPLICIT_RETURN]);
 
 fn lint_return(cx: &LateContext<'_>, emission_place: HirId, span: Span) {
-    let mut app = Applicability::MachineApplicable;
-    let snip = snippet_with_applicability(cx, span, "..", &mut app);
     span_lint_hir_and_then(
         cx,
         IMPLICIT_RETURN,
@@ -54,14 +52,20 @@ fn lint_return(cx: &LateContext<'_>, emission_place: HirId, span: Span) {
         span,
         "missing `return` statement",
         |diag| {
-            diag.span_suggestion(span, "add `return` as shown", format!("return {snip}"), app);
+            let mut app = Applicability::MachineApplicable;
+            let snip = snippet_with_applicability(cx, span, "..", &mut app);
+            diag.span_suggestion_with_style(
+                span,
+                "add `return` as shown",
+                format!("return {snip}"),
+                app,
+                SuggestionStyle::ShowAlways,
+            );
         },
     );
 }
 
 fn lint_break(cx: &LateContext<'_>, emission_place: HirId, break_span: Span, expr_span: Span) {
-    let mut app = Applicability::MachineApplicable;
-    let snip = snippet_with_context(cx, expr_span, break_span.ctxt(), "..", &mut app).0;
     span_lint_hir_and_then(
         cx,
         IMPLICIT_RETURN,
@@ -69,11 +73,14 @@ fn lint_break(cx: &LateContext<'_>, emission_place: HirId, break_span: Span, exp
         break_span,
         "missing `return` statement",
         |diag| {
-            diag.span_suggestion(
+            let mut app = Applicability::MachineApplicable;
+            let snip = snippet_with_context(cx, expr_span, break_span.ctxt(), "..", &mut app).0;
+            diag.span_suggestion_with_style(
                 break_span,
                 "change `break` to `return` as shown",
                 format!("return {snip}"),
                 app,
+                SuggestionStyle::ShowAlways,
             );
         },
     );
diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs
index f225c6e7f04..dd5908553e5 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::get_parent_expr;
 use clippy_utils::source::snippet_with_context;
@@ -117,11 +117,11 @@ fn get_int_max(ty: Ty<'_>) -> Option<u128> {
 
 fn get_const<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<(u128, BinOpKind, &'tcx Expr<'tcx>)> {
     if let ExprKind::Binary(op, l, r) = expr.kind {
-        let tr = cx.typeck_results();
-        if let Some(Constant::Int(c)) = constant(cx, tr, r) {
+        let ecx = ConstEvalCtxt::new(cx);
+        if let Some(Constant::Int(c)) = ecx.eval(r) {
             return Some((c, op.node, l));
         };
-        if let Some(Constant::Int(c)) = constant(cx, tr, l) {
+        if let Some(Constant::Int(c)) = ecx.eval(l) {
             return Some((c, invert_op(op.node)?, r));
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs
index 12ca6d43b27..0ef5b803a89 100644
--- a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs
+++ b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs
@@ -55,7 +55,6 @@ impl IncompatibleMsrv {
         }
     }
 
-    #[allow(clippy::cast_lossless)]
     fn get_def_id_version(&mut self, tcx: TyCtxt<'_>, def_id: DefId) -> RustcVersion {
         if let Some(version) = self.is_above_msrv.get(&def_id) {
             return *version;
@@ -67,9 +66,9 @@ impl IncompatibleMsrv {
                     since: StableSince::Version(version),
                     ..
                 } => Some(RustcVersion::new(
-                    version.major as _,
-                    version.minor as _,
-                    version.patch as _,
+                    version.major.into(),
+                    version.minor.into(),
+                    version.patch.into(),
                 )),
                 _ => None,
             }) {
diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
index 526b4e1fba0..2f9661c9ea3 100644
--- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
@@ -1,6 +1,6 @@
 use clippy_config::msrvs::{self, Msrv};
 use clippy_config::Conf;
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher::IfLet;
 use clippy_utils::ty::is_copy;
@@ -246,7 +246,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'a, 'tcx> {
                 && let parent_id = cx.tcx.parent_hir_id(expr.hir_id)
                 && let hir::Node::Expr(parent_expr) = cx.tcx.hir_node(parent_id)
                 && let hir::ExprKind::Index(_, index_expr, _) = parent_expr.kind
-                && let Some(Constant::Int(index_value)) = constant(cx, cx.typeck_results(), index_expr)
+                && let Some(Constant::Int(index_value)) = ConstEvalCtxt::new(cx).eval(index_expr)
                 && let Ok(index_value) = index_value.try_into()
                 && index_value < max_suggested_slice
 
diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
index 6729c7c8d10..3ac50b8f1fb 100644
--- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
@@ -1,7 +1,7 @@
 //! lint on indexing and slicing operations
 
 use clippy_config::Conf;
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::ty::{deref_chain, get_adt_inherent_method};
 use clippy_utils::{higher, is_from_proc_macro};
@@ -70,8 +70,6 @@ declare_clippy_lint! {
     ///
     /// Use instead:
     /// ```no_run
-    /// # #![allow(unused)]
-    ///
     /// # let x = vec![0; 5];
     /// # let y = [0, 1, 2, 3];
     /// x.get(2);
@@ -179,7 +177,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
                         return;
                     }
                     // Index is a constant uint.
-                    if let Some(constant) = constant(cx, cx.typeck_results(), index) {
+                    if let Some(constant) = ConstEvalCtxt::new(cx).eval(index) {
                         // only `usize` index is legal in rust array index
                         // leave other type to rustc
                         if let Constant::Int(off) = constant
@@ -217,14 +215,15 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
 /// Returns a tuple of options with the start and end (exclusive) values of
 /// the range. If the start or end is not constant, None is returned.
 fn to_const_range(cx: &LateContext<'_>, range: higher::Range<'_>, array_size: u128) -> (Option<u128>, Option<u128>) {
-    let s = range.start.map(|expr| constant(cx, cx.typeck_results(), expr));
+    let ecx = ConstEvalCtxt::new(cx);
+    let s = range.start.map(|expr| ecx.eval(expr));
     let start = match s {
         Some(Some(Constant::Int(x))) => Some(x),
         Some(_) => None,
         None => Some(0),
     };
 
-    let e = range.end.map(|expr| constant(cx, cx.typeck_results(), expr));
+    let e = range.end.map(|expr| ecx.eval(expr));
     let end = match e {
         Some(Some(Constant::Int(x))) => {
             if range.limits == RangeLimits::Closed {
diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
index fa7e7f6b76d..676d50c4951 100644
--- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
@@ -41,7 +41,6 @@ declare_clippy_lint! {
     /// ### Example
     /// ```no_run
     /// let infinite_iter = 0..;
-    /// # #[allow(unused)]
     /// [0..].iter().zip(infinite_iter.take_while(|x| *x > 5));
     /// ```
     #[clippy::version = "pre 1.29.0"]
diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs
index 0d3786dad4b..9eed7aa9243 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs
@@ -1,6 +1,6 @@
 //! lint on inherent implementations
 
-use clippy_utils::diagnostics::span_lint_and_note;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_lint_allowed;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::LocalDefId;
@@ -105,13 +105,14 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl {
         // `TyCtxt::crate_inherent_impls` doesn't have a defined order. Sort the lint output first.
         lint_spans.sort_by_key(|x| x.0.lo());
         for (span, first_span) in lint_spans {
-            span_lint_and_note(
+            span_lint_and_then(
                 cx,
                 MULTIPLE_INHERENT_IMPL,
                 span,
                 "multiple implementations of this structure",
-                Some(first_span),
-                "first implementation here",
+                |diag| {
+                    diag.span_note(first_span, "first implementation here");
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
index 30f2285bdd2..1929fbded3b 100644
--- a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
@@ -7,7 +7,7 @@ use rustc_span::Span;
 
 use clippy_utils::comparisons;
 use clippy_utils::comparisons::Rel;
-use clippy_utils::consts::{constant_full_int, FullInt};
+use clippy_utils::consts::{ConstEvalCtxt, FullInt};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::source::snippet;
 
@@ -95,7 +95,7 @@ fn upcast_comparison_bounds_err<'tcx>(
     invert: bool,
 ) {
     if let Some((lb, ub)) = lhs_bounds {
-        if let Some(norm_rhs_val) = constant_full_int(cx, cx.typeck_results(), rhs) {
+        if let Some(norm_rhs_val) = ConstEvalCtxt::new(cx).eval_full_int(rhs) {
             if rel == Rel::Eq || rel == Rel::Ne {
                 if norm_rhs_val < lb || norm_rhs_val > ub {
                     err_upcast_comparison(cx, span, lhs, rel == Rel::Ne);
diff --git a/src/tools/clippy/clippy_lints/src/large_include_file.rs b/src/tools/clippy/clippy_lints/src/large_include_file.rs
index c67da689aae..f2f841dcec3 100644
--- a/src/tools/clippy/clippy_lints/src/large_include_file.rs
+++ b/src/tools/clippy/clippy_lints/src/large_include_file.rs
@@ -1,5 +1,5 @@
 use clippy_config::Conf;
-use clippy_utils::diagnostics::span_lint_and_note;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::root_macro_call_first_node;
 use rustc_ast::LitKind;
 use rustc_hir::{Expr, ExprKind};
@@ -66,16 +66,18 @@ impl LateLintPass<'_> for LargeIncludeFile {
             && (cx.tcx.is_diagnostic_item(sym::include_bytes_macro, macro_call.def_id)
                 || cx.tcx.is_diagnostic_item(sym::include_str_macro, macro_call.def_id))
         {
-            span_lint_and_note(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 LARGE_INCLUDE_FILE,
                 expr.span.source_callsite(),
                 "attempted to include a large file",
-                None,
-                format!(
-                    "the configuration allows a maximum size of {} bytes",
-                    self.max_file_size
-                ),
+                |diag| {
+                    diag.note(format!(
+                        "the configuration allows a maximum size of {} bytes",
+                        self.max_file_size
+                    ));
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs
index 8fa63f3e8fd..b522c22a44d 100644
--- a/src/tools/clippy/clippy_lints/src/let_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::ty::{implements_trait, is_must_use_ty, match_type};
 use clippy_utils::{is_from_proc_macro, is_must_use_func_call, paths};
 use rustc_hir::{LetStmt, LocalSource, PatKind};
@@ -149,43 +149,53 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
                 GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
             });
             if contains_sync_guard {
-                span_lint_and_help(
+                #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+                span_lint_and_then(
                     cx,
                     LET_UNDERSCORE_LOCK,
                     local.span,
                     "non-binding `let` on a synchronization lock",
-                    None,
-                    "consider using an underscore-prefixed named \
-                            binding or dropping explicitly with `std::mem::drop`",
+                    |diag| {
+                        diag.help(
+                            "consider using an underscore-prefixed named \
+                                binding or dropping explicitly with `std::mem::drop`",
+                        );
+                    },
                 );
             } else if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait()
                 && implements_trait(cx, cx.typeck_results().expr_ty(init), future_trait_def_id, &[])
             {
-                span_lint_and_help(
+                #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+                span_lint_and_then(
                     cx,
                     LET_UNDERSCORE_FUTURE,
                     local.span,
                     "non-binding `let` on a future",
-                    None,
-                    "consider awaiting the future or dropping explicitly with `std::mem::drop`",
+                    |diag| {
+                        diag.help("consider awaiting the future or dropping explicitly with `std::mem::drop`");
+                    },
                 );
             } else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) {
-                span_lint_and_help(
+                #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+                span_lint_and_then(
                     cx,
                     LET_UNDERSCORE_MUST_USE,
                     local.span,
                     "non-binding `let` on an expression with `#[must_use]` type",
-                    None,
-                    "consider explicitly using expression value",
+                    |diag| {
+                        diag.help("consider explicitly using expression value");
+                    },
                 );
             } else if is_must_use_func_call(cx, init) {
-                span_lint_and_help(
+                #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+                span_lint_and_then(
                     cx,
                     LET_UNDERSCORE_MUST_USE,
                     local.span,
                     "non-binding `let` on a result of a `#[must_use]` function",
-                    None,
-                    "consider explicitly using function result",
+                    |diag| {
+                        diag.help("consider explicitly using function result");
+                    },
                 );
             }
 
@@ -204,18 +214,22 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
                     return;
                 }
 
-                span_lint_and_help(
+                span_lint_and_then(
                     cx,
                     LET_UNDERSCORE_UNTYPED,
                     local.span,
                     "non-binding `let` without a type annotation",
-                    Some(Span::new(
-                        local.pat.span.hi(),
-                        local.pat.span.hi() + BytePos(1),
-                        local.pat.span.ctxt(),
-                        local.pat.span.parent(),
-                    )),
-                    "consider adding a type annotation",
+                    |diag| {
+                        diag.span_help(
+                            Span::new(
+                                local.pat.span.hi(),
+                                local.pat.span.hi() + BytePos(1),
+                                local.pat.span.ctxt(),
+                                local.pat.span.parent(),
+                            ),
+                            "consider adding a type annotation",
+                        );
+                    },
                 );
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/lib.deprecated.rs b/src/tools/clippy/clippy_lints/src/lib.deprecated.rs
deleted file mode 100644
index 0d21261822d..00000000000
--- a/src/tools/clippy/clippy_lints/src/lib.deprecated.rs
+++ /dev/null
@@ -1,78 +0,0 @@
-// This file was generated by `cargo dev update_lints`.
-// Use that command to update this file and do not edit by hand.
-// Manual edits will be overwritten.
-
-{
-    store.register_removed(
-        "clippy::should_assert_eq",
-        "`assert!()` will be more flexible with RFC 2011",
-    );
-    store.register_removed(
-        "clippy::extend_from_slice",
-        "`.extend_from_slice(_)` is a faster way to extend a Vec by a slice",
-    );
-    store.register_removed(
-        "clippy::range_step_by_zero",
-        "`iterator.step_by(0)` panics nowadays",
-    );
-    store.register_removed(
-        "clippy::unstable_as_slice",
-        "`Vec::as_slice` has been stabilized in 1.7",
-    );
-    store.register_removed(
-        "clippy::unstable_as_mut_slice",
-        "`Vec::as_mut_slice` has been stabilized in 1.7",
-    );
-    store.register_removed(
-        "clippy::misaligned_transmute",
-        "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr",
-    );
-    store.register_removed(
-        "clippy::assign_ops",
-        "using compound assignment operators (e.g., `+=`) is harmless",
-    );
-    store.register_removed(
-        "clippy::if_let_redundant_pattern_matching",
-        "this lint has been changed to redundant_pattern_matching",
-    );
-    store.register_removed(
-        "clippy::unsafe_vector_initialization",
-        "the replacement suggested by this lint had substantially different behavior",
-    );
-    store.register_removed(
-        "clippy::unused_collect",
-        "`collect` has been marked as #[must_use] in rustc and that covers all cases of this lint",
-    );
-    store.register_removed(
-        "clippy::replace_consts",
-        "associated-constants `MIN`/`MAX` of integers are preferred to `{min,max}_value()` and module constants",
-    );
-    store.register_removed(
-        "clippy::regex_macro",
-        "the regex! macro has been removed from the regex crate in 2018",
-    );
-    store.register_removed(
-        "clippy::find_map",
-        "this lint has been replaced by `manual_find_map`, a more specific lint",
-    );
-    store.register_removed(
-        "clippy::filter_map",
-        "this lint has been replaced by `manual_filter_map`, a more specific lint",
-    );
-    store.register_removed(
-        "clippy::pub_enum_variant_names",
-        "set the `avoid-breaking-exported-api` config option to `false` to enable the `enum_variant_names` lint for public items",
-    );
-    store.register_removed(
-        "clippy::wrong_pub_self_convention",
-        "set the `avoid-breaking-exported-api` config option to `false` to enable the `wrong_self_convention` lint for public items",
-    );
-    store.register_removed(
-        "clippy::maybe_misused_cfg",
-        "this lint has been replaced by `unexpected_cfgs`",
-    );
-    store.register_removed(
-        "clippy::mismatched_target_os",
-        "this lint has been replaced by `unexpected_cfgs`",
-    );
-}
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 22d23a17509..ce13a9afef5 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -8,13 +8,11 @@
 #![feature(iter_intersperse)]
 #![feature(iter_partition_in_place)]
 #![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(lint_reasons))]
 #![feature(never_type)]
 #![feature(rustc_private)]
 #![feature(stmt_expr_attributes)]
 #![feature(unwrap_infallible)]
 #![recursion_limit = "512"]
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![allow(
     clippy::missing_docs_in_private_items,
     clippy::must_use_candidate,
@@ -65,13 +63,11 @@ extern crate clippy_utils;
 #[macro_use]
 extern crate declare_clippy_lint;
 
-#[cfg(feature = "internal")]
-pub mod deprecated_lints;
 #[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))]
 mod utils;
 
 mod declared_lints;
-mod renamed_lints;
+mod deprecated_lints;
 
 // begin lints modules, do not remove this comment, it’s used in `update_lints`
 mod absolute_paths;
@@ -373,6 +369,7 @@ mod unsafe_removed_from_name;
 mod unused_async;
 mod unused_io_amount;
 mod unused_peekable;
+mod unused_result_ok;
 mod unused_rounding;
 mod unused_self;
 mod unused_unit;
@@ -496,7 +493,7 @@ pub fn explain(name: &str) -> i32 {
         // Check if the lint has configuration
         let mut mdconf = get_configuration_metadata();
         let name = name.to_ascii_lowercase();
-        mdconf.retain(|cconf| cconf.lints.contains(&name));
+        mdconf.retain(|cconf| cconf.lints.contains(&&*name));
         if !mdconf.is_empty() {
             println!("### Configuration for {}:\n", info.lint.name_lower());
             for conf in mdconf {
@@ -532,10 +529,14 @@ fn register_categories(store: &mut rustc_lint::LintStore) {
 /// Used in `./src/driver.rs`.
 #[expect(clippy::too_many_lines)]
 pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
-    register_removed_non_tool_lints(store);
     register_categories(store);
 
-    include!("lib.deprecated.rs");
+    for (old_name, new_name) in deprecated_lints::RENAMED {
+        store.register_renamed(old_name, new_name);
+    }
+    for (name, reason) in deprecated_lints::DEPRECATED {
+        store.register_removed(name, reason);
+    }
 
     #[cfg(feature = "internal")]
     {
@@ -670,6 +671,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(move |_| Box::new(missing_doc::MissingDoc::new(conf)));
     store.register_late_pass(|_| Box::new(missing_inline::MissingInline));
     store.register_late_pass(move |_| Box::new(exhaustive_items::ExhaustiveItems));
+    store.register_late_pass(|_| Box::new(unused_result_ok::UnusedResultOk));
     store.register_late_pass(|_| Box::new(match_result_ok::MatchResultOk));
     store.register_late_pass(|_| Box::new(partialeq_ne_impl::PartialEqNeImpl));
     store.register_late_pass(|_| Box::new(unused_io_amount::UnusedIoAmount));
@@ -819,7 +821,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(conf)));
     store.register_late_pass(move |_| Box::new(manual_rotate::ManualRotate));
     store.register_late_pass(move |_| Box::new(operators::Operators::new(conf)));
-    store.register_late_pass(|_| Box::<std_instead_of_core::StdReexports>::default());
+    store.register_late_pass(move |_| Box::new(std_instead_of_core::StdReexports::new(conf)));
     store.register_late_pass(move |_| Box::new(instant_subtraction::InstantSubtraction::new(conf)));
     store.register_late_pass(|_| Box::new(partialeq_to_none::PartialeqToNone));
     store.register_late_pass(move |_| Box::new(manual_clamp::ManualClamp::new(conf)));
@@ -908,68 +910,8 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(move |_| Box::new(macro_metavars_in_unsafe::ExprMetavarsInUnsafe::new(conf)));
     store.register_late_pass(move |_| Box::new(string_patterns::StringPatterns::new(conf)));
     store.register_early_pass(|| Box::new(field_scoped_visibility_modifiers::FieldScopedVisibilityModifiers));
-    store.register_late_pass(|_| Box::new(set_contains_or_insert::HashsetInsertAfterContains));
+    store.register_late_pass(|_| Box::new(set_contains_or_insert::SetContainsOrInsert));
     store.register_early_pass(|| Box::new(byte_char_slices::ByteCharSlice));
     store.register_early_pass(|| Box::new(cfg_not_test::CfgNotTest));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
-
-#[rustfmt::skip]
-fn register_removed_non_tool_lints(store: &mut rustc_lint::LintStore) {
-    store.register_removed(
-        "should_assert_eq",
-        "`assert!()` will be more flexible with RFC 2011",
-    );
-    store.register_removed(
-        "extend_from_slice",
-        "`.extend_from_slice(_)` is a faster way to extend a Vec by a slice",
-    );
-    store.register_removed(
-        "range_step_by_zero",
-        "`iterator.step_by(0)` panics nowadays",
-    );
-    store.register_removed(
-        "unstable_as_slice",
-        "`Vec::as_slice` has been stabilized in 1.7",
-    );
-    store.register_removed(
-        "unstable_as_mut_slice",
-        "`Vec::as_mut_slice` has been stabilized in 1.7",
-    );
-    store.register_removed(
-        "misaligned_transmute",
-        "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr",
-    );
-    store.register_removed(
-        "assign_ops",
-        "using compound assignment operators (e.g., `+=`) is harmless",
-    );
-    store.register_removed(
-        "if_let_redundant_pattern_matching",
-        "this lint has been changed to redundant_pattern_matching",
-    );
-    store.register_removed(
-        "unsafe_vector_initialization",
-        "the replacement suggested by this lint had substantially different behavior",
-    );
-    store.register_removed(
-        "reverse_range_loop",
-        "this lint is now included in reversed_empty_ranges",
-    );
-}
-
-/// Register renamed lints.
-///
-/// Used in `./src/driver.rs`.
-pub fn register_renamed(ls: &mut rustc_lint::LintStore) {
-    for (old_name, new_name) in renamed_lints::RENAMED_LINTS {
-        ls.register_renamed(old_name, new_name);
-    }
-}
-
-// only exists to let the dogfood integration test works.
-// Don't run clippy as an executable directly
-#[allow(dead_code)]
-fn main() {
-    panic!("Please use the cargo-clippy executable");
-}
diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs
index b685d1dad1a..259e4d6c08f 100644
--- a/src/tools/clippy/clippy_lints/src/literal_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs
@@ -2,13 +2,13 @@
 //! floating-point literal expressions.
 
 use clippy_config::Conf;
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::numeric_literal::{NumericLiteral, Radix};
 use clippy_utils::source::snippet_opt;
 use rustc_ast::ast::{Expr, ExprKind, LitKind};
 use rustc_ast::token;
 use rustc_errors::Applicability;
-use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_lint::{EarlyContext, EarlyLintPass, Lint, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
@@ -159,63 +159,39 @@ enum WarningType {
 }
 
 impl WarningType {
-    fn display(&self, suggested_format: String, cx: &EarlyContext<'_>, span: Span) {
+    fn lint_and_text(&self) -> (&'static Lint, &'static str, &'static str) {
         match self {
-            Self::MistypedLiteralSuffix => span_lint_and_sugg(
-                cx,
+            Self::MistypedLiteralSuffix => (
                 MISTYPED_LITERAL_SUFFIXES,
-                span,
                 "mistyped literal suffix",
                 "did you mean to write",
-                suggested_format,
-                Applicability::MaybeIncorrect,
             ),
-            Self::UnreadableLiteral => span_lint_and_sugg(
-                cx,
-                UNREADABLE_LITERAL,
-                span,
-                "long literal lacking separators",
-                "consider",
-                suggested_format,
-                Applicability::MachineApplicable,
-            ),
-            Self::LargeDigitGroups => span_lint_and_sugg(
-                cx,
-                LARGE_DIGIT_GROUPS,
-                span,
-                "digit groups should be smaller",
-                "consider",
-                suggested_format,
-                Applicability::MachineApplicable,
-            ),
-            Self::InconsistentDigitGrouping => span_lint_and_sugg(
-                cx,
+            Self::UnreadableLiteral => (UNREADABLE_LITERAL, "long literal lacking separators", "consider"),
+            Self::LargeDigitGroups => (LARGE_DIGIT_GROUPS, "digit groups should be smaller", "consider"),
+            Self::InconsistentDigitGrouping => (
                 INCONSISTENT_DIGIT_GROUPING,
-                span,
                 "digits grouped inconsistently by underscores",
                 "consider",
-                suggested_format,
-                Applicability::MachineApplicable,
             ),
-            Self::DecimalRepresentation => span_lint_and_sugg(
-                cx,
+            Self::DecimalRepresentation => (
                 DECIMAL_LITERAL_REPRESENTATION,
-                span,
                 "integer literal has a better hexadecimal representation",
                 "consider",
-                suggested_format,
-                Applicability::MachineApplicable,
             ),
-            Self::UnusualByteGroupings => span_lint_and_sugg(
-                cx,
+            Self::UnusualByteGroupings => (
                 UNUSUAL_BYTE_GROUPINGS,
-                span,
                 "digits of hex, binary or octal literal not in groups of equal size",
                 "consider",
-                suggested_format,
-                Applicability::MachineApplicable,
             ),
-        };
+        }
+    }
+
+    fn display(&self, num_lit: &NumericLiteral<'_>, cx: &EarlyContext<'_>, span: Span) {
+        let (lint, message, try_msg) = self.lint_and_text();
+        #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+        span_lint_and_then(cx, lint, span, message, |diag| {
+            diag.span_suggestion(span, try_msg, num_lit.format(), Applicability::MaybeIncorrect);
+        });
     }
 }
 
@@ -293,7 +269,7 @@ impl LiteralDigitGrouping {
                     WarningType::DecimalRepresentation | WarningType::MistypedLiteralSuffix => true,
                 };
                 if should_warn {
-                    warning_type.display(num_lit.format(), cx, span);
+                    warning_type.display(&num_lit, cx, span);
                 }
             }
         }
@@ -346,11 +322,14 @@ impl LiteralDigitGrouping {
                 }
             }
             *part = main_part;
-            let mut sugg = num_lit.format();
-            sugg.push('_');
-            sugg.push(missing_char);
-            sugg.push_str(last_group);
-            WarningType::MistypedLiteralSuffix.display(sugg, cx, span);
+            let (lint, message, try_msg) = WarningType::MistypedLiteralSuffix.lint_and_text();
+            span_lint_and_then(cx, lint, span, message, |diag| {
+                let mut sugg = num_lit.format();
+                sugg.push('_');
+                sugg.push(missing_char);
+                sugg.push_str(last_group);
+                diag.span_suggestion(span, try_msg, sugg, Applicability::MaybeIncorrect);
+            });
             false
         } else {
             true
@@ -471,7 +450,7 @@ impl DecimalLiteralRepresentation {
             let hex = format!("{val:#X}");
             let num_lit = NumericLiteral::new(&hex, num_lit.suffix, false);
             let _: Result<(), ()> = Self::do_lint(num_lit.integer).map_err(|warning_type| {
-                warning_type.display(num_lit.format(), cx, span);
+                warning_type.display(&num_lit, cx, span);
             });
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs
index f0ee64d714e..73a23615c2d 100644
--- a/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs
@@ -2,6 +2,7 @@ use super::{make_iterator_snippet, IncrementVisitor, InitializeVisitor, EXPLICIT
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::{get_enclosing_block, is_integer_const};
+use rustc_ast::Label;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_block, walk_expr};
 use rustc_hir::{Expr, Pat};
@@ -17,6 +18,7 @@ pub(super) fn check<'tcx>(
     arg: &'tcx Expr<'_>,
     body: &'tcx Expr<'_>,
     expr: &'tcx Expr<'_>,
+    label: Option<Label>,
 ) {
     // Look for variables that are incremented once per loop iteration.
     let mut increment_visitor = IncrementVisitor::new(cx);
@@ -34,7 +36,7 @@ pub(super) fn check<'tcx>(
             {
                 let mut applicability = Applicability::MaybeIncorrect;
                 let span = expr.span.with_hi(arg.span.hi());
-
+                let loop_label = label.map_or(String::new(), |l| format!("{}: ", l.ident.name));
                 let int_name = match ty.map(Ty::kind) {
                     // usize or inferred
                     Some(ty::Uint(UintTy::Usize)) | None => {
@@ -45,7 +47,7 @@ pub(super) fn check<'tcx>(
                             format!("the variable `{name}` is used as a loop counter"),
                             "consider using",
                             format!(
-                                "for ({name}, {}) in {}.enumerate()",
+                                "{loop_label}for ({name}, {}) in {}.enumerate()",
                                 snippet_with_applicability(cx, pat.span, "item", &mut applicability),
                                 make_iterator_snippet(cx, arg, &mut applicability),
                             ),
@@ -68,7 +70,7 @@ pub(super) fn check<'tcx>(
                             span,
                             "consider using",
                             format!(
-                                "for ({name}, {}) in (0_{int_name}..).zip({})",
+                                "{loop_label}for ({name}, {}) in (0_{int_name}..).zip({})",
                                 snippet_with_applicability(cx, pat.span, "item", &mut applicability),
                                 make_iterator_snippet(cx, arg, &mut applicability),
                             ),
diff --git a/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs b/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs
index 6922533fbe9..185d834beca 100644
--- a/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs
@@ -1,8 +1,9 @@
 use super::FOR_KV_MAP;
-use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{pat_is_wild, sugg};
+use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty;
@@ -40,13 +41,13 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx
                     format!("you seem to want to iterate on a map's {kind}s"),
                     |diag| {
                         let map = sugg::Sugg::hir(cx, arg, "map");
-                        multispan_sugg(
-                            diag,
+                        diag.multipart_suggestion(
                             "use the corresponding method",
                             vec![
                                 (pat_span, snippet(cx, new_pat_span, kind).into_owned()),
                                 (arg_span, format!("{}.{kind}s{mutbl}()", map.maybe_par())),
                             ],
+                            Applicability::MachineApplicable,
                         );
                     },
                 );
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs b/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs
index b00a082bb8c..57434f35544 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_then};
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet;
 use clippy_utils::{match_def_path, paths, SpanlessEq};
 use rustc_errors::Applicability;
@@ -38,11 +38,10 @@ fn report_lint(cx: &LateContext<'_>, pop_span: Span, pop_stmt_kind: PopStmt<'_>,
             };
 
             let loop_replacement = format!("while let Some({}) = {}.pop()", pat, snippet(cx, receiver_span, ".."));
-            multispan_sugg_with_applicability(
-                diag,
+            diag.multipart_suggestion(
                 "consider using a `while..let` loop",
+                vec![(loop_span, loop_replacement), (pop_span, pop_replacement)],
                 Applicability::MachineApplicable,
-                [(loop_span, loop_replacement), (pop_span, pop_replacement)],
             );
         },
     );
diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs
index 7c2a8098af2..92ccc0cc0a1 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs
@@ -25,6 +25,7 @@ mod while_let_on_iterator;
 use clippy_config::msrvs::Msrv;
 use clippy_config::Conf;
 use clippy_utils::higher;
+use rustc_ast::Label;
 use rustc_hir::{Expr, ExprKind, LoopSource, Pat};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
@@ -448,7 +449,7 @@ declare_clippy_lint! {
     #[clippy::version = "1.80.0"]
     pub WHILE_FLOAT,
     nursery,
-    "while loops comaparing floating point values"
+    "while loops comparing floating point values"
 }
 
 declare_clippy_lint! {
@@ -760,6 +761,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
             body,
             loop_id,
             span,
+            label,
         }) = for_loop
         {
             // we don't want to check expanded macros
@@ -768,7 +770,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
             if body.span.from_expansion() {
                 return;
             }
-            self.check_for_loop(cx, pat, arg, body, expr, span);
+            self.check_for_loop(cx, pat, arg, body, expr, span, label);
             if let ExprKind::Block(block, _) = body.kind {
                 never_loop::check(cx, block, loop_id, span, for_loop.as_ref());
             }
@@ -808,6 +810,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
 }
 
 impl Loops {
+    #[allow(clippy::too_many_arguments)]
     fn check_for_loop<'tcx>(
         &self,
         cx: &LateContext<'tcx>,
@@ -816,11 +819,12 @@ impl Loops {
         body: &'tcx Expr<'_>,
         expr: &'tcx Expr<'_>,
         span: Span,
+        label: Option<Label>,
     ) {
         let is_manual_memcpy_triggered = manual_memcpy::check(cx, pat, arg, body, expr);
         if !is_manual_memcpy_triggered {
             needless_range_loop::check(cx, pat, arg, body, expr);
-            explicit_counter_loop::check(cx, pat, arg, body, expr);
+            explicit_counter_loop::check(cx, pat, arg, body, expr, label);
         }
         self.check_for_loop_arg(cx, pat, arg);
         for_kv_map::check(cx, pat, arg, body);
diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
index de7ec81bc01..e18e4374667 100644
--- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
@@ -1,11 +1,12 @@
 use super::NEEDLESS_RANGE_LOOP;
-use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::has_iter_method;
 use clippy_utils::visitors::is_local_used;
 use clippy_utils::{contains_name, higher, is_integer_const, sugg, SpanlessEq};
 use rustc_ast::ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{BinOpKind, BorrowKind, Closure, Expr, ExprKind, HirId, Mutability, Pat, PatKind, QPath};
@@ -145,8 +146,7 @@ pub(super) fn check<'tcx>(
                         arg.span,
                         format!("the loop variable `{}` is used to index `{indexed}`", ident.name),
                         |diag| {
-                            multispan_sugg(
-                                diag,
+                            diag.multipart_suggestion(
                                 "consider using an iterator and enumerate()",
                                 vec![
                                     (pat.span, format!("({}, <item>)", ident.name)),
@@ -155,6 +155,7 @@ pub(super) fn check<'tcx>(
                                         format!("{indexed}.{method}().enumerate(){method_1}{method_2}"),
                                     ),
                                 ],
+                                Applicability::HasPlaceholders,
                             );
                         },
                     );
@@ -171,10 +172,10 @@ pub(super) fn check<'tcx>(
                         arg.span,
                         format!("the loop variable `{}` is only used to index `{indexed}`", ident.name),
                         |diag| {
-                            multispan_sugg(
-                                diag,
+                            diag.multipart_suggestion(
                                 "consider using an iterator",
                                 vec![(pat.span, "<item>".to_string()), (arg.span, repl)],
+                                Applicability::HasPlaceholders,
                             );
                         },
                     );
diff --git a/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs b/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs
index 40ccfec02be..51e21aa9734 100644
--- a/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs
@@ -1,7 +1,8 @@
 use super::UNUSED_ENUMERATE_INDEX;
-use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet;
 use clippy_utils::{pat_is_wild, sugg};
+use rustc_errors::Applicability;
 use rustc_hir::def::DefKind;
 use rustc_hir::{Expr, ExprKind, Pat, PatKind};
 use rustc_lint::LateContext;
@@ -28,13 +29,13 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>, arg: &Expr<'_
             "you seem to use `.enumerate()` and immediately discard the index",
             |diag| {
                 let base_iter = sugg::Sugg::hir(cx, self_arg, "base iter");
-                multispan_sugg(
-                    diag,
+                diag.multipart_suggestion(
                     "remove the `.enumerate()` call",
                     vec![
                         (pat.span, snippet(cx, elem.span, "..").into_owned()),
                         (arg.span, base_iter.to_string()),
                     ],
+                    Applicability::MachineApplicable,
                 );
             },
         );
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs b/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs
index e7b3a2c4973..cc1bd5929d0 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs
@@ -1,5 +1,5 @@
 use super::WHILE_IMMUTABLE_CONDITION;
-use clippy_utils::consts::constant;
+use clippy_utils::consts::ConstEvalCtxt;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::usage::mutated_variables;
 use rustc_hir::def::{DefKind, Res};
@@ -10,7 +10,7 @@ use rustc_lint::LateContext;
 use std::ops::ControlFlow;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) {
-    if constant(cx, cx.typeck_results(), cond).is_some() {
+    if ConstEvalCtxt::new(cx).eval(cond).is_some() {
         // A pure constant condition (e.g., `while false`) is not linted.
         return;
     }
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
index 194dd4752f9..c171fa1c622 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
@@ -14,7 +14,7 @@ use rustc_span::symbol::sym;
 use rustc_span::Symbol;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-    if let Some(higher::WhileLet { if_then, let_pat, let_expr, .. }) = higher::WhileLet::hir(expr)
+    if let Some(higher::WhileLet { if_then, let_pat, let_expr, label, .. }) = higher::WhileLet::hir(expr)
         // check for `Some(..)` pattern
         && let PatKind::TupleStruct(ref pat_path, some_pat, _) = let_pat.kind
         && is_res_lang_ctor(cx, cx.qpath_res(pat_path, let_pat.hir_id), LangItem::OptionSome)
@@ -27,6 +27,9 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         && !uses_iter(cx, &iter_expr_struct, if_then)
     {
         let mut applicability = Applicability::MachineApplicable;
+
+        let loop_label = label.map_or(String::new(), |l| format!("{}: ", l.ident.name));
+
         let loop_var = if let Some(some_pat) = some_pat.first() {
             if is_refutable(cx, some_pat) {
                 // Refutable patterns don't work with for loops.
@@ -57,7 +60,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             expr.span.with_hi(let_expr.span.hi()),
             "this loop could be written as a `for` loop",
             "try",
-            format!("for {loop_var} in {iterator}{by_ref}"),
+            format!("{loop_label}for {loop_var} in {iterator}{by_ref}"),
             applicability,
         );
     }
diff --git a/src/tools/clippy/clippy_lints/src/manual_clamp.rs b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
index a79ad018a04..4123c933660 100644
--- a/src/tools/clippy/clippy_lints/src/manual_clamp.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
@@ -1,13 +1,13 @@
 use clippy_config::msrvs::{self, Msrv};
 use clippy_config::Conf;
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
 use clippy_utils::higher::If;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::implements_trait;
 use clippy_utils::visitors::is_const_evaluatable;
 use clippy_utils::{
-    eq_expr_value, in_constant, is_diag_trait_item, is_trait_method, path_res, path_to_local_id, peel_blocks,
+    eq_expr_value, is_diag_trait_item, is_in_const_context, is_trait_method, path_res, path_to_local_id, peel_blocks,
     peel_blocks_with_stmt, MaybePath,
 };
 use itertools::Itertools;
@@ -122,8 +122,9 @@ impl<'tcx> ClampSuggestion<'tcx> {
         if max_type != min_type {
             return false;
         }
-        if let Some(max) = constant(cx, cx.typeck_results(), self.params.max)
-            && let Some(min) = constant(cx, cx.typeck_results(), self.params.min)
+        let ecx = ConstEvalCtxt::new(cx);
+        if let Some(max) = ecx.eval(self.params.max)
+            && let Some(min) = ecx.eval(self.params.min)
             && let Some(ord) = Constant::partial_cmp(cx.tcx, max_type, &min, &max)
         {
             ord != Ordering::Greater
@@ -146,7 +147,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualClamp {
         if !self.msrv.meets(msrvs::CLAMP) {
             return;
         }
-        if !expr.span.from_expansion() && !in_constant(cx, expr.hir_id) {
+        if !expr.span.from_expansion() && !is_in_const_context(cx) {
             let suggestion = is_if_elseif_else_pattern(cx, expr)
                 .or_else(|| is_max_min_pattern(cx, expr))
                 .or_else(|| is_call_max_min_pattern(cx, expr))
@@ -159,7 +160,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualClamp {
     }
 
     fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
-        if !self.msrv.meets(msrvs::CLAMP) || in_constant(cx, block.hir_id) {
+        if !self.msrv.meets(msrvs::CLAMP) || is_in_const_context(cx) {
             return;
         }
         for suggestion in is_two_if_pattern(cx, block) {
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 03416ba96de..6bdc79129a9 100644
--- a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_opt;
 use clippy_utils::{is_from_proc_macro, path_to_local};
@@ -95,8 +95,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
                     || cx.tcx.features().declared(sym!(const_float_classify))
             )
             && let [first, second, const_1, const_2] = exprs
-            && let Some(const_1) = constant(cx, cx.typeck_results(), const_1)
-            && let Some(const_2) = constant(cx, cx.typeck_results(), const_2)
+            && let ecx = ConstEvalCtxt::new(cx)
+            && let Some(const_1) = ecx.eval(const_1)
+            && let Some(const_2) = ecx.eval(const_2)
             && path_to_local(first).is_some_and(|f| path_to_local(second).is_some_and(|s| f == s))
             // The actual infinity check, we also allow `NEG_INFINITY` before` INFINITY` just in
             // case somebody does that for some reason
diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
index a9f21d34e4c..31c37c3bc3b 100644
--- a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
@@ -3,7 +3,7 @@ use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::matching_root_macro_call;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{higher, in_constant, path_to_local, peel_ref_operators};
+use clippy_utils::{higher, is_in_const_context, path_to_local, peel_ref_operators};
 use rustc_ast::ast::RangeLimits;
 use rustc_ast::LitKind::{Byte, Char};
 use rustc_errors::Applicability;
@@ -95,7 +95,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
             return;
         }
 
-        if in_constant(cx, expr.hir_id) && !self.msrv.meets(msrvs::IS_ASCII_DIGIT_CONST) {
+        if is_in_const_context(cx) && !self.msrv.meets(msrvs::IS_ASCII_DIGIT_CONST) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
index 78a750f0dcd..6cf5d272d7d 100644
--- a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
@@ -1,9 +1,9 @@
 use clippy_config::msrvs::{self, Msrv};
 use clippy_config::Conf;
-use clippy_utils::consts::{constant_full_int, FullInt};
+use clippy_utils::consts::{ConstEvalCtxt, FullInt};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::{in_constant, path_to_local};
+use clippy_utils::{is_in_const_context, path_to_local};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, Node, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
             && add_rhs.span.ctxt() == ctxt
             && !in_external_macro(cx.sess(), expr.span)
             && self.msrv.meets(msrvs::REM_EUCLID)
-            && (self.msrv.meets(msrvs::REM_EUCLID_CONST) || !in_constant(cx, expr.hir_id))
+            && (self.msrv.meets(msrvs::REM_EUCLID_CONST) || !is_in_const_context(cx))
             && let Some(const1) = check_for_unsigned_int_constant(cx, rem_rhs)
             && let Some((const2, add_other)) = check_for_either_unsigned_int_constant(cx, add_lhs, add_rhs)
             && let ExprKind::Binary(rem2_op, rem2_lhs, rem2_rhs) = add_other.kind
@@ -117,7 +117,7 @@ fn check_for_either_unsigned_int_constant<'a>(
 }
 
 fn check_for_unsigned_int_constant<'a>(cx: &'a LateContext<'_>, expr: &'a Expr<'_>) -> Option<u128> {
-    let int_const = constant_full_int(cx, cx.typeck_results(), expr)?;
+    let int_const = ConstEvalCtxt::new(cx).eval_full_int(expr)?;
     match int_const {
         FullInt::S(s) => s.try_into().ok(),
         FullInt::U(u) => Some(u),
diff --git a/src/tools/clippy/clippy_lints/src/manual_rotate.rs b/src/tools/clippy/clippy_lints/src/manual_rotate.rs
index a517a4d5075..07537fc65c0 100644
--- a/src/tools/clippy/clippy_lints/src/manual_rotate.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_rotate.rs
@@ -1,6 +1,6 @@
 use std::fmt::Display;
 
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::sugg;
 use rustc_errors::Applicability;
@@ -66,7 +66,7 @@ fn parse_shift<'tcx>(
             BinOpKind::Shr => ShiftDirection::Right,
             _ => return None,
         };
-        let const_expr = constant(cx, cx.typeck_results(), r)?;
+        let const_expr = ConstEvalCtxt::new(cx).eval(r)?;
         if let Constant::Int(shift) = const_expr {
             return Some((dir, shift, l));
         }
diff --git a/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs b/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs
index 429ee2637c2..b24a0f4695a 100644
--- a/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::{expr_or_init, in_constant, std_or_core};
+use clippy_utils::{expr_or_init, is_in_const_context, std_or_core};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -44,7 +44,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualSliceSizeCalculation {
             && BinOpKind::Mul == op.node
             && !expr.span.from_expansion()
             // Does not apply inside const because size_of_val is not cost in stable.
-            && !in_constant(cx, expr.hir_id)
+            && !is_in_const_context(cx)
             && let Some(receiver) = simplify(cx, left, right)
         {
             let ctxt = expr.span.ctxt();
diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs
index 686ecccf829..85cabd2800a 100644
--- a/src/tools/clippy/clippy_lints/src/manual_strip.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs
@@ -1,11 +1,12 @@
 use clippy_config::msrvs::{self, Msrv};
 use clippy_config::Conf;
-use clippy_utils::consts::{constant, Constant};
-use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet;
 use clippy_utils::usage::mutated_variables;
 use clippy_utils::{eq_expr_value, higher, match_def_path, paths};
 use rustc_ast::ast::LitKind;
+use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind};
@@ -14,6 +15,7 @@ use rustc_middle::ty;
 use rustc_session::impl_lint_pass;
 use rustc_span::source_map::Spanned;
 use rustc_span::Span;
+use std::iter;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -108,19 +110,19 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
                     format!("stripping a {kind_word} manually"),
                     |diag| {
                         diag.span_note(test_span, format!("the {kind_word} was tested here"));
-                        multispan_sugg(
-                            diag,
+                        diag.multipart_suggestion(
                             format!("try using the `strip_{kind_word}` method"),
-                            vec![(
+                            iter::once((
                                 test_span,
                                 format!(
                                     "if let Some(<stripped>) = {}.strip_{kind_word}({}) ",
                                     snippet(cx, target_arg.span, ".."),
                                     snippet(cx, pattern.span, "..")
                                 ),
-                            )]
-                            .into_iter()
-                            .chain(strippings.into_iter().map(|span| (span, "<stripped>".into()))),
+                            ))
+                            .chain(strippings.into_iter().map(|span| (span, "<stripped>".into())))
+                            .collect(),
+                            Applicability::HasPlaceholders,
                         );
                     },
                 );
@@ -145,7 +147,7 @@ fn len_arg<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx E
 
 // Returns the length of the `expr` if it's a constant string or char.
 fn constant_length(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u128> {
-    let value = constant(cx, cx.typeck_results(), expr)?;
+    let value = ConstEvalCtxt::new(cx).eval(expr)?;
     match value {
         Constant::Str(value) => Some(value.len() as u128),
         Constant::Char(value) => Some(value.len_utf8() as u128),
@@ -183,9 +185,9 @@ fn peel_ref<'a>(expr: &'a Expr<'_>) -> &'a Expr<'a> {
     }
 }
 
-// Find expressions where `target` is stripped using the length of `pattern`.
-// We'll suggest replacing these expressions with the result of the `strip_{prefix,suffix}`
-// method.
+/// Find expressions where `target` is stripped using the length of `pattern`.
+/// We'll suggest replacing these expressions with the result of the `strip_{prefix,suffix}`
+/// method.
 fn find_stripping<'tcx>(
     cx: &LateContext<'tcx>,
     strip_kind: StripKind,
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 f1acc4b2174..8f8390b6f3f 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
@@ -10,7 +10,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::higher::IfLetOrMatch;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::implements_trait;
-use clippy_utils::{in_constant, is_default_equivalent, peel_blocks, span_contains_comment};
+use clippy_utils::{is_default_equivalent, is_in_const_context, peel_blocks, span_contains_comment};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -174,7 +174,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualUnwrapOrDefault {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         if let Some(if_let_or_match) = IfLetOrMatch::parse(cx, expr)
             && !expr.span.from_expansion()
-            && !in_constant(cx, expr.hir_id)
+            && !is_in_const_context(cx)
         {
             handle(cx, if_let_or_match, expr);
         }
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
index 85a08f81c2f..2d4c8daf5cb 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::constant_simple;
+use clippy_utils::consts::ConstEvalCtxt;
 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;
@@ -69,7 +69,7 @@ fn check_and_lint<'tcx>(
         && 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()
+        && ConstEvalCtxt::new(cx).eval_simple(else_expr).is_some()
     {
         lint(cx, expr, let_expr, ty_name, or_body_snippet, indent);
     }
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_ref_pats.rs b/src/tools/clippy/clippy_lints/src/matches/match_ref_pats.rs
index aba4c85c59e..5445ee1f042 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_ref_pats.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_ref_pats.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::{snippet, walk_span_to_context};
 use clippy_utils::sugg::Sugg;
 use core::iter::once;
@@ -54,7 +54,11 @@ where
 
     span_lint_and_then(cx, MATCH_REF_PATS, expr.span, title, |diag| {
         if !expr.span.from_expansion() {
-            multispan_sugg(diag, msg, first_sugg.chain(remaining_suggs));
+            diag.multipart_suggestion(
+                msg,
+                first_sugg.chain(remaining_suggs).collect(),
+                Applicability::MachineApplicable,
+            );
         }
     });
 }
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
index 8d22ceb47f8..91e40e4275c 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{is_refutable, peel_hir_pat_refs, recurse_or_patterns};
 use rustc_errors::Applicability;
@@ -148,23 +148,27 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
             Applicability::MaybeIncorrect,
         ),
         variants => {
-            let mut suggestions: Vec<_> = variants.iter().copied().map(format_suggestion).collect();
-            let message = if adt_def.is_variant_list_non_exhaustive() || has_external_hidden {
-                suggestions.push("_".into());
-                "wildcard matches known variants and will also match future added variants"
+            let (message, add_wildcard) = if adt_def.is_variant_list_non_exhaustive() || has_external_hidden {
+                (
+                    "wildcard matches known variants and will also match future added variants",
+                    true,
+                )
             } else {
-                "wildcard match will also match any future added variants"
+                ("wildcard match will also match any future added variants", false)
             };
 
-            span_lint_and_sugg(
-                cx,
-                WILDCARD_ENUM_MATCH_ARM,
-                wildcard_span,
-                message,
-                "try",
-                suggestions.join(" | "),
-                Applicability::MaybeIncorrect,
-            );
+            span_lint_and_then(cx, WILDCARD_ENUM_MATCH_ARM, wildcard_span, message, |diag| {
+                let mut suggestions: Vec<_> = variants.iter().copied().map(format_suggestion).collect();
+                if add_wildcard {
+                    suggestions.push("_".into());
+                }
+                diag.span_suggestion(
+                    wildcard_span,
+                    "try",
+                    suggestions.join(" | "),
+                    Applicability::MaybeIncorrect,
+                );
+            });
         },
     };
 }
@@ -176,9 +180,8 @@ enum CommonPrefixSearcher<'a> {
 }
 impl<'a> CommonPrefixSearcher<'a> {
     fn with_path(&mut self, path: &'a [PathSegment<'a>]) {
-        match path {
-            [path @ .., _] => self.with_prefix(path),
-            [] => (),
+        if let [path @ .., _] = path {
+            self.with_prefix(path);
         }
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
index 310675d01a2..d0d2025878e 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_note;
 use clippy_utils::macros::{is_panic, root_macro_call};
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::is_local_used;
-use clippy_utils::{in_constant, is_wild, peel_blocks_with_stmt};
+use clippy_utils::{is_in_const_context, is_wild, peel_blocks_with_stmt};
 use rustc_hir::{Arm, Expr, PatKind};
 use rustc_lint::LateContext;
 use rustc_span::symbol::{kw, sym};
@@ -11,7 +11,7 @@ use super::MATCH_WILD_ERR_ARM;
 
 pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<'tcx>]) {
     // `unwrap`/`expect` is not (yet) const, so we want to allow this in const contexts for now
-    if in_constant(cx, ex.hir_id) {
+    if is_in_const_context(cx) {
         return;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index cec3504ed8d..cf5377e0725 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -27,7 +27,7 @@ mod wild_in_or_pats;
 use clippy_config::msrvs::{self, Msrv};
 use clippy_config::Conf;
 use clippy_utils::source::walk_span_to_context;
-use clippy_utils::{higher, in_constant, is_direct_expn_of, is_span_match, span_contains_cfg};
+use clippy_utils::{higher, is_direct_expn_of, is_in_const_context, is_span_match, span_contains_cfg};
 use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat, PatKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
@@ -1069,7 +1069,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
                     match_str_case_mismatch::check(cx, ex, arms);
                     redundant_guards::check(cx, arms, &self.msrv);
 
-                    if !in_constant(cx, expr.hir_id) {
+                    if !is_in_const_context(cx) {
                         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);
@@ -1098,7 +1098,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
                             else_expr,
                         );
                     }
-                    if !in_constant(cx, expr.hir_id) {
+                    if !is_in_const_context(cx) {
                         manual_unwrap_or::check_if_let(
                             cx,
                             expr,
diff --git a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs
index 45b375dbe3d..71f211be925 100644
--- a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, constant_full_int, mir_to_const, FullInt};
+use clippy_utils::consts::{mir_to_const, ConstEvalCtxt, FullInt};
 use clippy_utils::diagnostics::span_lint_and_note;
 use core::cmp::Ordering;
 use rustc_hir::{Arm, Expr, PatKind, RangeEnd};
@@ -33,22 +33,20 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
         .filter_map(|arm| {
             if let Arm { pat, guard: None, .. } = *arm {
                 if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind {
-                    let lhs_const = match lhs {
-                        Some(lhs) => constant(cx, cx.typeck_results(), lhs)?,
-                        None => {
-                            let min_val_const = ty.numeric_min_val(cx.tcx)?;
-                            mir_to_const(cx, mir::Const::from_ty_const(min_val_const, ty, cx.tcx))?
-                        },
+                    let lhs_const = if let Some(lhs) = lhs {
+                        ConstEvalCtxt::new(cx).eval(lhs)?
+                    } else {
+                        let min_val_const = ty.numeric_min_val(cx.tcx)?;
+                        mir_to_const(cx.tcx, mir::Const::from_ty_const(min_val_const, ty, cx.tcx))?
                     };
-                    let rhs_const = match rhs {
-                        Some(rhs) => constant(cx, cx.typeck_results(), rhs)?,
-                        None => {
-                            let max_val_const = ty.numeric_max_val(cx.tcx)?;
-                            mir_to_const(cx, mir::Const::from_ty_const(max_val_const, ty, cx.tcx))?
-                        },
+                    let rhs_const = if let Some(rhs) = rhs {
+                        ConstEvalCtxt::new(cx).eval(rhs)?
+                    } else {
+                        let max_val_const = ty.numeric_max_val(cx.tcx)?;
+                        mir_to_const(cx.tcx, mir::Const::from_ty_const(max_val_const, ty, cx.tcx))?
                     };
-                    let lhs_val = lhs_const.int_value(cx, ty)?;
-                    let rhs_val = rhs_const.int_value(cx, ty)?;
+                    let lhs_val = lhs_const.int_value(cx.tcx, ty)?;
+                    let rhs_val = rhs_const.int_value(cx.tcx, ty)?;
                     let rhs_bound = match range_end {
                         RangeEnd::Included => EndBound::Included(rhs_val),
                         RangeEnd::Excluded => EndBound::Excluded(rhs_val),
@@ -60,7 +58,7 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
                 }
 
                 if let PatKind::Lit(value) = pat.kind {
-                    let value = constant_full_int(cx, cx.typeck_results(), value)?;
+                    let value = ConstEvalCtxt::new(cx).eval_full_int(value)?;
                     return Some(SpannedRange {
                         span: pat.span,
                         node: (value, EndBound::Included(value)),
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
index c2c0fbf439d..8222c3057f7 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
@@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::matching_root_macro_call;
 use clippy_utils::source::snippet;
 use clippy_utils::visitors::{for_each_expr_without_closures, is_local_used};
-use clippy_utils::{in_constant, path_to_local};
+use clippy_utils::{is_in_const_context, path_to_local};
 use rustc_ast::{BorrowKind, LitKind};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
@@ -116,7 +116,7 @@ fn check_method_calls<'tcx>(
         // `s if s.is_empty()` becomes ""
         // `arr if arr.is_empty()` becomes []
 
-        if ty.is_str() && !in_constant(cx, if_expr.hir_id) {
+        if ty.is_str() && !is_in_const_context(cx) {
             r#""""#.into()
         } else if slice_like {
             "[]".into()
diff --git a/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs b/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs
index 316b2f63e4e..2154cd5b24a 100644
--- a/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_hir::{Pat, PatKind, QPath};
 use rustc_lint::LateContext;
 use rustc_middle::ty;
@@ -15,13 +15,15 @@ pub(crate) fn check(cx: &LateContext<'_>, pat: &Pat<'_>) {
         && fields.len() == def.non_enum_variant().fields.len()
         && !def.non_enum_variant().is_field_list_non_exhaustive()
     {
-        span_lint_and_help(
+        #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+        span_lint_and_then(
             cx,
             REST_PAT_IN_FULLY_BOUND_STRUCTS,
             pat.span,
             "unnecessary use of `..` pattern in struct binding. All fields were already bound",
-            None,
-            "consider removing `..` from this binding",
+            |diag| {
+                diag.help("consider removing `..` from this binding");
+            },
         );
     }
 }
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 99fdbcff890..24dea03601c 100644
--- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
@@ -1,12 +1,17 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 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;
+use clippy_utils::ty::implements_trait;
+use clippy_utils::{
+    is_lint_allowed, is_unit_expr, peel_blocks, peel_hir_pat_refs, peel_middle_ty_refs, peel_n_hir_expr_refs,
+};
+use core::ops::ControlFlow;
+use rustc_arena::DroplessArena;
 use rustc_errors::Applicability;
-use rustc_hir::{Arm, BindingMode, Block, Expr, ExprKind, Pat, PatKind};
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::intravisit::{walk_pat, Visitor};
+use rustc_hir::{Arm, Expr, ExprKind, HirId, Pat, PatKind, QPath};
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, AdtDef, ParamEnv, TyCtxt, TypeckResults, VariantDef};
 use rustc_span::{sym, Span};
 
 use super::{MATCH_BOOL, SINGLE_MATCH, SINGLE_MATCH_ELSE};
@@ -27,52 +32,58 @@ fn empty_arm_has_comment(cx: &LateContext<'_>, span: Span) -> bool {
 }
 
 #[rustfmt::skip]
-pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
-    if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() {
-        if expr.span.from_expansion() {
-            // Don't lint match expressions present in
-            // macro_rules! block
-            return;
-        }
-        if let PatKind::Or(..) = arms[0].pat.kind {
-            // don't lint for or patterns for now, this makes
-            // the lint noisy in unnecessary situations
-            return;
-        }
-        let els = arms[1].body;
-        let els = if is_unit_expr(peel_blocks(els)) && !empty_arm_has_comment(cx, els.span) {
+pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>], expr: &'tcx Expr<'_>) {
+    if let [arm1, arm2] = arms
+        && arm1.guard.is_none()
+        && arm2.guard.is_none()
+        && !expr.span.from_expansion()
+        // don't lint for or patterns for now, this makes
+        // the lint noisy in unnecessary situations
+        && !matches!(arm1.pat.kind, PatKind::Or(..))
+    {
+        let els = if is_unit_expr(peel_blocks(arm2.body)) && !empty_arm_has_comment(cx, arm2.body.span) {
             None
-        } else if let ExprKind::Block(Block { stmts, expr: block_expr, .. }, _) = els.kind {
-            if stmts.len() == 1 && block_expr.is_none() || stmts.is_empty() && block_expr.is_some() {
+        } else if let ExprKind::Block(block, _) = arm2.body.kind {
+            if matches!((block.stmts, block.expr), ([], Some(_)) | ([_], None)) {
                 // single statement/expr "else" block, don't lint
                 return;
             }
             // block with 2+ statements or 1 expr and 1+ statement
-            Some(els)
+            Some(arm2.body)
         } else {
             // not a block or an empty block w/ comments, don't lint
             return;
         };
 
-        let ty = cx.typeck_results().expr_ty(ex);
-        if (*ty.kind() != ty::Bool || is_lint_allowed(cx, MATCH_BOOL, ex.hir_id)) &&
-            (check_single_pattern(arms) || check_opt_like(cx, arms, ty)) {
-            report_single_pattern(cx, ex, arms, expr, els);
+        let typeck = cx.typeck_results();
+        if *typeck.expr_ty(ex).peel_refs().kind() != ty::Bool || is_lint_allowed(cx, MATCH_BOOL, ex.hir_id) {
+            let mut v = PatVisitor {
+                typeck,
+                has_enum: false,
+            };
+            if v.visit_pat(arm2.pat).is_break() {
+                return;
+            }
+            if v.has_enum {
+                let cx = PatCtxt {
+                    tcx: cx.tcx,
+                    param_env: cx.param_env,
+                    typeck,
+                    arena: DroplessArena::default(),
+                };
+                let mut state = PatState::Other;
+                if !(state.add_pat(&cx, arm2.pat) || state.add_pat(&cx, arm1.pat)) {
+                    // Don't lint if the pattern contains an enum which doesn't have a wild match.
+                    return;
+                }
+            }
+
+            report_single_pattern(cx, ex, arm1, expr, els);
         }
     }
 }
 
-fn check_single_pattern(arms: &[Arm<'_>]) -> bool {
-    is_wild(arms[1].pat)
-}
-
-fn report_single_pattern(
-    cx: &LateContext<'_>,
-    ex: &Expr<'_>,
-    arms: &[Arm<'_>],
-    expr: &Expr<'_>,
-    els: Option<&Expr<'_>>,
-) {
+fn report_single_pattern(cx: &LateContext<'_>, ex: &Expr<'_>, arm: &Arm<'_>, expr: &Expr<'_>, els: Option<&Expr<'_>>) {
     let lint = if els.is_some() { SINGLE_MATCH_ELSE } else { SINGLE_MATCH };
     let ctxt = expr.span.ctxt();
     let mut app = Applicability::MachineApplicable;
@@ -80,9 +91,9 @@ fn report_single_pattern(
         format!(" else {}", expr_block(cx, els, ctxt, "..", Some(expr.span), &mut app))
     });
 
-    let (pat, pat_ref_count) = peel_hir_pat_refs(arms[0].pat);
+    let (pat, pat_ref_count) = peel_hir_pat_refs(arm.pat);
     let (msg, sugg) = if let PatKind::Path(_) | PatKind::Lit(_) = pat.kind
-        && let (ty, ty_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(ex))
+        && let (ty, ty_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(ex))
         && let Some(spe_trait_id) = cx.tcx.lang_items().structural_peq_trait()
         && let Some(pe_trait_id) = cx.tcx.lang_items().eq_trait()
         && (ty.is_integral()
@@ -114,17 +125,17 @@ fn report_single_pattern(
             snippet(cx, ex.span, ".."),
             // PartialEq for different reference counts may not exist.
             "&".repeat(ref_count_diff),
-            snippet(cx, arms[0].pat.span, ".."),
-            expr_block(cx, arms[0].body, ctxt, "..", Some(expr.span), &mut app),
+            snippet(cx, arm.pat.span, ".."),
+            expr_block(cx, arm.body, ctxt, "..", Some(expr.span), &mut app),
         );
         (msg, sugg)
     } else {
         let msg = "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`";
         let sugg = format!(
             "if let {} = {} {}{els_str}",
-            snippet(cx, arms[0].pat.span, ".."),
+            snippet(cx, arm.pat.span, ".."),
             snippet(cx, ex.span, ".."),
-            expr_block(cx, arms[0].body, ctxt, "..", Some(expr.span), &mut app),
+            expr_block(cx, arm.body, ctxt, "..", Some(expr.span), &mut app),
         );
         (msg, sugg)
     };
@@ -132,106 +143,227 @@ fn report_single_pattern(
     span_lint_and_sugg(cx, lint, expr.span, msg, "try", sugg, app);
 }
 
-fn check_opt_like<'a>(cx: &LateContext<'a>, arms: &[Arm<'_>], ty: Ty<'a>) -> bool {
-    // We don't want to lint if the second arm contains an enum which could
-    // have more variants in the future.
-    form_exhaustive_matches(cx, ty, arms[0].pat, arms[1].pat)
+struct PatVisitor<'tcx> {
+    typeck: &'tcx TypeckResults<'tcx>,
+    has_enum: bool,
 }
-
-/// Returns `true` if all of the types in the pattern are enums which we know
-/// won't be expanded in the future
-fn pat_in_candidate_enum<'a>(cx: &LateContext<'a>, ty: Ty<'a>, pat: &Pat<'_>) -> bool {
-    let mut paths_and_types = Vec::new();
-    collect_pat_paths(&mut paths_and_types, cx, pat, ty);
-    paths_and_types.iter().all(|ty| in_candidate_enum(cx, *ty))
+impl<'tcx> Visitor<'tcx> for PatVisitor<'tcx> {
+    type Result = ControlFlow<()>;
+    fn visit_pat(&mut self, pat: &'tcx Pat<'_>) -> Self::Result {
+        if matches!(pat.kind, PatKind::Binding(..)) {
+            ControlFlow::Break(())
+        } else {
+            self.has_enum |= self.typeck.pat_ty(pat).ty_adt_def().map_or(false, AdtDef::is_enum);
+            walk_pat(self, pat)
+        }
+    }
 }
 
-/// Returns `true` if the given type is an enum we know won't be expanded in the future
-fn in_candidate_enum(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
-    // list of candidate `Enum`s we know will never get any more members
-    let candidates = [sym::Cow, sym::Option, sym::Result];
+/// The context needed to manipulate a `PatState`.
+struct PatCtxt<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    param_env: ParamEnv<'tcx>,
+    typeck: &'tcx TypeckResults<'tcx>,
+    arena: DroplessArena,
+}
 
-    for candidate_ty in candidates {
-        if is_type_diagnostic_item(cx, ty, candidate_ty) {
-            return true;
+/// State for tracking whether a match can become non-exhaustive by adding a variant to a contained
+/// enum.
+///
+/// This treats certain std enums as if they will never be extended.
+enum PatState<'a> {
+    /// Either a wild match or an uninteresting type. Uninteresting types include:
+    /// * builtin types (e.g. `i32` or `!`)
+    /// * A struct/tuple/array containing only uninteresting types.
+    /// * A std enum containing only uninteresting types.
+    Wild,
+    /// A std enum we know won't be extended. Tracks the states of each variant separately.
+    ///
+    /// This is not used for `Option` since it uses the current pattern to track it's state.
+    StdEnum(&'a mut [PatState<'a>]),
+    /// Either the initial state for a pattern or a non-std enum. There is currently no need to
+    /// distinguish these cases.
+    ///
+    /// For non-std enums there's no need to track the state of sub-patterns as the state of just
+    /// this pattern on it's own is enough for linting. Consider two cases:
+    /// * This enum has no wild match. This case alone is enough to determine we can lint.
+    /// * This enum has a wild match and therefore all sub-patterns also have a wild match.
+    ///
+    /// In both cases the sub patterns are not needed to determine whether to lint.
+    Other,
+}
+impl<'a> PatState<'a> {
+    /// Adds a set of patterns as a product type to the current state. Returns whether or not the
+    /// current state is a wild match after the merge.
+    fn add_product_pat<'tcx>(
+        &mut self,
+        cx: &'a PatCtxt<'tcx>,
+        pats: impl IntoIterator<Item = &'tcx Pat<'tcx>>,
+    ) -> bool {
+        // Ideally this would actually keep track of the state separately for each pattern. Doing so would
+        // require implementing something similar to exhaustiveness checking which is a significant increase
+        // in complexity.
+        //
+        // For now treat this as a wild match only if all the sub-patterns are wild
+        let is_wild = pats.into_iter().all(|p| {
+            let mut state = Self::Other;
+            state.add_pat(cx, p)
+        });
+        if is_wild {
+            *self = Self::Wild;
         }
+        is_wild
     }
-    false
-}
 
-/// Collects types from the given pattern
-fn collect_pat_paths<'a>(acc: &mut Vec<Ty<'a>>, cx: &LateContext<'a>, pat: &Pat<'_>, ty: Ty<'a>) {
-    match pat.kind {
-        PatKind::Tuple(inner, _) => inner.iter().for_each(|p| {
-            let p_ty = cx.typeck_results().pat_ty(p);
-            collect_pat_paths(acc, cx, p, p_ty);
-        }),
-        PatKind::TupleStruct(..) | PatKind::Binding(BindingMode::NONE, .., None) | PatKind::Path(_) => {
-            acc.push(ty);
-        },
-        _ => {},
+    /// Attempts to get the state for the enum variant, initializing the current state if necessary.
+    fn get_std_enum_variant<'tcx>(
+        &mut self,
+        cx: &'a PatCtxt<'tcx>,
+        adt: AdtDef<'tcx>,
+        path: &'tcx QPath<'_>,
+        hir_id: HirId,
+    ) -> Option<(&mut Self, &'tcx VariantDef)> {
+        let states = match self {
+            Self::Wild => return None,
+            Self::Other => {
+                *self = Self::StdEnum(cx.arena.alloc_from_iter((0..adt.variants().len()).map(|_| Self::Other)));
+                let Self::StdEnum(x) = self else {
+                    unreachable!();
+                };
+                x
+            },
+            Self::StdEnum(x) => x,
+        };
+        let i = match cx.typeck.qpath_res(path, hir_id) {
+            Res::Def(DefKind::Ctor(..), id) => adt.variant_index_with_ctor_id(id),
+            Res::Def(DefKind::Variant, id) => adt.variant_index_with_id(id),
+            _ => return None,
+        };
+        Some((&mut states[i.as_usize()], adt.variant(i)))
     }
-}
 
-/// Returns true if the given arm of pattern matching contains wildcard patterns.
-fn contains_only_wilds(pat: &Pat<'_>) -> bool {
-    match pat.kind {
-        PatKind::Wild => true,
-        PatKind::Tuple(inner, _) | PatKind::TupleStruct(_, inner, ..) => inner.iter().all(contains_only_wilds),
-        _ => false,
+    fn check_all_wild_enum(&mut self) -> bool {
+        if let Self::StdEnum(states) = self
+            && states.iter().all(|s| matches!(s, Self::Wild))
+        {
+            *self = Self::Wild;
+            true
+        } else {
+            false
+        }
     }
-}
 
-/// Returns true if the given patterns forms only exhaustive matches that don't contain enum
-/// patterns without a wildcard.
-fn form_exhaustive_matches<'a>(cx: &LateContext<'a>, ty: Ty<'a>, left: &Pat<'_>, right: &Pat<'_>) -> bool {
-    match (&left.kind, &right.kind) {
-        (PatKind::Wild, _) | (_, PatKind::Wild) => true,
-        (PatKind::Tuple(left_in, left_pos), PatKind::Tuple(right_in, right_pos)) => {
-            // We don't actually know the position and the presence of the `..` (dotdot) operator
-            // in the arms, so we need to evaluate the correct offsets here in order to iterate in
-            // both arms at the same time.
-            let left_pos = left_pos.as_opt_usize();
-            let right_pos = right_pos.as_opt_usize();
-            let len = max(
-                left_in.len() + usize::from(left_pos.is_some()),
-                right_in.len() + usize::from(right_pos.is_some()),
-            );
-            let mut left_pos = left_pos.unwrap_or(usize::MAX);
-            let mut right_pos = right_pos.unwrap_or(usize::MAX);
-            let mut left_dot_space = 0;
-            let mut right_dot_space = 0;
-            for i in 0..len {
-                let mut found_dotdot = false;
-                if i == left_pos {
-                    left_dot_space += 1;
-                    if left_dot_space < len - left_in.len() {
-                        left_pos += 1;
-                    }
-                    found_dotdot = true;
-                }
-                if i == right_pos {
-                    right_dot_space += 1;
-                    if right_dot_space < len - right_in.len() {
-                        right_pos += 1;
-                    }
-                    found_dotdot = true;
-                }
-                if found_dotdot {
-                    continue;
+    #[expect(clippy::similar_names)]
+    fn add_struct_pats<'tcx>(
+        &mut self,
+        cx: &'a PatCtxt<'tcx>,
+        pat: &'tcx Pat<'tcx>,
+        path: &'tcx QPath<'tcx>,
+        single_pat: Option<&'tcx Pat<'tcx>>,
+        pats: impl IntoIterator<Item = &'tcx Pat<'tcx>>,
+    ) -> bool {
+        let ty::Adt(adt, _) = *cx.typeck.pat_ty(pat).kind() else {
+            // Should never happen
+            *self = Self::Wild;
+            return true;
+        };
+        if adt.is_struct() {
+            return if let Some(pat) = single_pat
+                && adt.non_enum_variant().fields.len() == 1
+            {
+                self.add_pat(cx, pat)
+            } else {
+                self.add_product_pat(cx, pats)
+            };
+        }
+        match cx.tcx.get_diagnostic_name(adt.did()) {
+            Some(sym::Option) => {
+                if let Some(pat) = single_pat {
+                    self.add_pat(cx, pat)
+                } else {
+                    *self = Self::Wild;
+                    true
                 }
-                if !contains_only_wilds(&left_in[i - left_dot_space])
-                    && !contains_only_wilds(&right_in[i - right_dot_space])
+            },
+            Some(sym::Result | sym::Cow) => {
+                let Some((state, variant)) = self.get_std_enum_variant(cx, adt, path, pat.hir_id) else {
+                    return matches!(self, Self::Wild);
+                };
+                let is_wild = if let Some(pat) = single_pat
+                    && variant.fields.len() == 1
                 {
-                    return false;
-                }
-            }
-            true
-        },
-        (PatKind::TupleStruct(..), PatKind::Path(_)) => pat_in_candidate_enum(cx, ty, right),
-        (PatKind::TupleStruct(..), PatKind::TupleStruct(_, inner, _)) => {
-            pat_in_candidate_enum(cx, ty, right) && inner.iter().all(contains_only_wilds)
-        },
-        _ => false,
+                    state.add_pat(cx, pat)
+                } else {
+                    state.add_product_pat(cx, pats)
+                };
+                is_wild && self.check_all_wild_enum()
+            },
+            _ => matches!(self, Self::Wild),
+        }
+    }
+
+    /// Adds the pattern into the current state. Returns whether or not the current state is a wild
+    /// match after the merge.
+    #[expect(clippy::similar_names)]
+    fn add_pat<'tcx>(&mut self, cx: &'a PatCtxt<'tcx>, pat: &'tcx Pat<'_>) -> bool {
+        match pat.kind {
+            PatKind::Path(_)
+                if match *cx.typeck.pat_ty(pat).peel_refs().kind() {
+                    ty::Adt(adt, _) => adt.is_enum() || (adt.is_struct() && !adt.non_enum_variant().fields.is_empty()),
+                    ty::Tuple(tys) => !tys.is_empty(),
+                    ty::Array(_, len) => len.try_eval_target_usize(cx.tcx, cx.param_env) != Some(1),
+                    ty::Slice(..) => true,
+                    _ => false,
+                } =>
+            {
+                matches!(self, Self::Wild)
+            },
+
+            // Patterns for things which can only contain a single sub-pattern.
+            PatKind::Binding(_, _, _, Some(pat)) | PatKind::Ref(pat, _) | PatKind::Box(pat) | PatKind::Deref(pat) => {
+                self.add_pat(cx, pat)
+            },
+            PatKind::Tuple([sub_pat], pos)
+                if pos.as_opt_usize().is_none() || cx.typeck.pat_ty(pat).tuple_fields().len() == 1 =>
+            {
+                self.add_pat(cx, sub_pat)
+            },
+            PatKind::Slice([sub_pat], _, []) | PatKind::Slice([], _, [sub_pat])
+                if let ty::Array(_, len) = *cx.typeck.pat_ty(pat).kind()
+                    && len.try_eval_target_usize(cx.tcx, cx.param_env) == Some(1) =>
+            {
+                self.add_pat(cx, sub_pat)
+            },
+
+            PatKind::Or(pats) => pats.iter().any(|p| self.add_pat(cx, p)),
+            PatKind::Tuple(pats, _) => self.add_product_pat(cx, pats),
+            PatKind::Slice(head, _, tail) => self.add_product_pat(cx, head.iter().chain(tail)),
+
+            PatKind::TupleStruct(ref path, pats, _) => self.add_struct_pats(
+                cx,
+                pat,
+                path,
+                if let [pat] = pats { Some(pat) } else { None },
+                pats.iter(),
+            ),
+            PatKind::Struct(ref path, pats, _) => self.add_struct_pats(
+                cx,
+                pat,
+                path,
+                if let [pat] = pats { Some(pat.pat) } else { None },
+                pats.iter().map(|p| p.pat),
+            ),
+
+            PatKind::Wild
+            | PatKind::Binding(_, _, _, None)
+            | PatKind::Lit(_)
+            | PatKind::Range(..)
+            | PatKind::Path(_)
+            | PatKind::Never
+            | PatKind::Err(_) => {
+                *self = PatState::Wild;
+                true
+            },
+        }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/matches/try_err.rs b/src/tools/clippy/clippy_lints/src/matches/try_err.rs
index dd489fc250b..b7ffa8b8a78 100644
--- a/src/tools/clippy/clippy_lints/src/matches/try_err.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/try_err.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{get_parent_expr, is_res_lang_ctor, path_res};
@@ -48,29 +48,28 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine
             return;
         };
 
-        let expr_err_ty = cx.typeck_results().expr_ty(err_arg);
-        let span = hygiene::walk_chain(err_arg.span, try_arg.span.ctxt());
-        let mut applicability = Applicability::MachineApplicable;
-        let origin_snippet = snippet_with_applicability(cx, span, "_", &mut applicability);
-        let ret_prefix = if get_parent_expr(cx, expr).map_or(false, |e| matches!(e.kind, ExprKind::Ret(_))) {
-            "" // already returns
-        } else {
-            "return "
-        };
-        let suggestion = if err_ty == expr_err_ty {
-            format!("{ret_prefix}{prefix}{origin_snippet}{suffix}")
-        } else {
-            format!("{ret_prefix}{prefix}{origin_snippet}.into(){suffix}")
-        };
-
-        span_lint_and_sugg(
+        span_lint_and_then(
             cx,
             TRY_ERR,
             expr.span,
             "returning an `Err(_)` with the `?` operator",
-            "try",
-            suggestion,
-            applicability,
+            |diag| {
+                let expr_err_ty = cx.typeck_results().expr_ty(err_arg);
+                let span = hygiene::walk_chain(err_arg.span, try_arg.span.ctxt());
+                let mut applicability = Applicability::MachineApplicable;
+                let origin_snippet = snippet_with_applicability(cx, span, "_", &mut applicability);
+                let ret_prefix = if get_parent_expr(cx, expr).map_or(false, |e| matches!(e.kind, ExprKind::Ret(_))) {
+                    "" // already returns
+                } else {
+                    "return "
+                };
+                let suggestion = if err_ty == expr_err_ty {
+                    format!("{ret_prefix}{prefix}{origin_snippet}{suffix}")
+                } else {
+                    format!("{ret_prefix}{prefix}{origin_snippet}.into(){suffix}")
+                };
+                diag.span_suggestion(expr.span, "try", suggestion, applicability);
+            },
         );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
index 20f3722e173..2a8a5fcc3b6 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
@@ -1,5 +1,5 @@
 use super::{contains_return, BIND_INSTEAD_OF_MAP};
-use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::peel_blocks;
 use clippy_utils::source::{snippet, snippet_with_context};
 use clippy_utils::visitors::find_all_ret_expressions;
@@ -136,15 +136,16 @@ impl BindInsteadOfMap {
             return false;
         };
         span_lint_and_then(cx, BIND_INSTEAD_OF_MAP, expr.span, msg, |diag| {
-            multispan_sugg_with_applicability(
-                diag,
-                "try",
+            diag.multipart_suggestion(
+                format!("use `{}` instead", self.good_method_name),
+                std::iter::once((span, self.good_method_name.into()))
+                    .chain(
+                        suggs
+                            .into_iter()
+                            .map(|(span1, span2)| (span1, snippet(cx, span2, "_").into())),
+                    )
+                    .collect(),
                 Applicability::MachineApplicable,
-                std::iter::once((span, self.good_method_name.into())).chain(
-                    suggs
-                        .into_iter()
-                        .map(|(span1, span2)| (span1, snippet(cx, span2, "_").into())),
-                ),
             );
         });
         true
diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs
index 926bd06bacb..e0826b53004 100644
--- a/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_with_context;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
@@ -29,19 +29,22 @@ pub(super) fn check(
             sym::RcWeak | sym::ArcWeak => "Weak",
             _ => return,
         };
-
-        // Sometimes unnecessary ::<_> after Rc/Arc/Weak
-        let mut app = Applicability::Unspecified;
-        let snippet = snippet_with_context(cx, receiver.span, expr.span.ctxt(), "..", &mut app).0;
-
-        span_lint_and_sugg(
+        span_lint_and_then(
             cx,
             CLONE_ON_REF_PTR,
             expr.span,
             "using `.clone()` on a ref-counted pointer",
-            "try",
-            format!("{caller_type}::<{}>::clone(&{snippet})", subst.type_at(0)),
-            app,
+            |diag| {
+                // Sometimes unnecessary ::<_> after Rc/Arc/Weak
+                let mut app = Applicability::Unspecified;
+                let snippet = snippet_with_context(cx, receiver.span, expr.span.ctxt(), "..", &mut app).0;
+                diag.span_suggestion(
+                    expr.span,
+                    "try",
+                    format!("{caller_type}::<{}>::clone(&{snippet})", subst.type_at(0)),
+                    app,
+                );
+            },
         );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs b/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs
index eab536b88a5..2ab0401947c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::get_parent_expr;
 use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_hir as hir;
@@ -33,6 +33,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
         span = expr.span;
     }
     let lint_msg = format!("`{lint_unary}FileType::is_file()` only {verb} regular files");
-    let help_msg = format!("use `{help_unary}FileType::is_dir()` instead");
-    span_lint_and_help(cx, FILETYPE_IS_FILE, span, lint_msg, None, help_msg);
+
+    #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+    span_lint_and_then(cx, FILETYPE_IS_FILE, span, lint_msg, |diag| {
+        diag.help(format!("use `{help_unary}FileType::is_dir()` instead"));
+    });
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs
index 455274a4428..c6285c87a26 100644
--- a/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs
@@ -1,5 +1,5 @@
 use super::utils::derefs_to_slice;
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::get_parent_expr;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::is_type_diagnostic_item;
@@ -19,9 +19,7 @@ pub(super) fn check<'tcx>(
 ) {
     // Note: we don't want to lint `get_mut().unwrap` for `HashMap` or `BTreeMap`,
     // because they do not implement `IndexMut`
-    let mut applicability = Applicability::MachineApplicable;
     let expr_ty = cx.typeck_results().expr_ty(recv);
-    let get_args_str = snippet_with_applicability(cx, get_arg.span, "..", &mut applicability);
     let caller_type = if derefs_to_slice(cx, recv, expr_ty).is_some() {
         "slice"
     } else if is_type_diagnostic_item(cx, expr_ty, sym::Vec) {
@@ -58,24 +56,34 @@ pub(super) fn check<'tcx>(
     };
 
     let mut_str = if is_mut { "_mut" } else { "" };
-    let borrow_str = if !needs_ref {
-        ""
-    } else if is_mut {
-        "&mut "
-    } else {
-        "&"
-    };
 
-    span_lint_and_sugg(
+    span_lint_and_then(
         cx,
         GET_UNWRAP,
         span,
-        format!("called `.get{mut_str}().unwrap()` on a {caller_type}. Using `[]` is more clear and more concise"),
-        "try",
-        format!(
-            "{borrow_str}{}[{get_args_str}]",
-            snippet_with_applicability(cx, recv.span, "..", &mut applicability)
-        ),
-        applicability,
+        format!("called `.get{mut_str}().unwrap()` on a {caller_type}"),
+        |diag| {
+            let mut applicability = Applicability::MachineApplicable;
+            let get_args_str = snippet_with_applicability(cx, get_arg.span, "..", &mut applicability);
+
+            let borrow_str = if !needs_ref {
+                ""
+            } else if is_mut {
+                "&mut "
+            } else {
+                "&"
+            };
+
+            diag.span_suggestion_with_style(
+                span,
+                "using `[]` is clearer and more concise",
+                format!(
+                    "{borrow_str}{}[{get_args_str}]",
+                    snippet_with_applicability(cx, recv.span, "..", &mut applicability)
+                ),
+                applicability,
+                rustc_errors::SuggestionStyle::ShowAlways,
+            );
+        },
     );
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
index c510cd915d0..519091406cc 100644
--- a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::ty::{implements_trait, peel_mid_ty_refs};
-use clippy_utils::{is_diag_item_method, is_diag_trait_item};
+use clippy_utils::ty::implements_trait;
+use clippy_utils::{is_diag_item_method, is_diag_trait_item, peel_middle_ty_refs};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -14,7 +14,7 @@ pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv
         && is_clone_like(cx, method_name, method_def_id)
         && let return_type = cx.typeck_results().expr_ty(expr)
         && let input_type = cx.typeck_results().expr_ty(recv)
-        && let (input_type, ref_count) = peel_mid_ty_refs(input_type)
+        && let (input_type, ref_count) = peel_middle_ty_refs(input_type)
         && !(ref_count > 0 && is_diag_trait_item(cx, method_def_id, sym::ToOwned))
         && let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did()))
         && return_type == input_type
diff --git a/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs b/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs
index 210e4ae0a7b..22d896433f0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs
@@ -2,7 +2,7 @@
 
 use super::IS_DIGIT_ASCII_RADIX;
 use clippy_config::msrvs::{self, Msrv};
-use clippy_utils::consts::{constant_full_int, FullInt};
+use clippy_utils::consts::{ConstEvalCtxt, FullInt};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use rustc_errors::Applicability;
@@ -24,7 +24,7 @@ pub(super) fn check<'tcx>(
         return;
     }
 
-    if let Some(radix_val) = constant_full_int(cx, cx.typeck_results(), radix) {
+    if let Some(radix_val) = ConstEvalCtxt::new(cx).eval_full_int(radix) {
         let (num, replacement) = match radix_val {
             FullInt::S(10) | FullInt::U(10) => (10, "is_ascii_digit"),
             FullInt::S(16) | FullInt::U(16) => (16, "is_ascii_hexdigit"),
diff --git a/src/tools/clippy/clippy_lints/src/methods/is_empty.rs b/src/tools/clippy/clippy_lints/src/methods/is_empty.rs
index d921b7ea14f..cc82f6cfd63 100644
--- a/src/tools/clippy/clippy_lints/src/methods/is_empty.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/is_empty.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::constant_is_empty;
+use clippy_utils::consts::ConstEvalCtxt;
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::{find_binding_init, path_to_local};
 use rustc_hir::{Expr, HirId};
@@ -18,7 +18,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, receiver: &Expr<'_
     if !receiver.span.eq_ctxt(init_expr.span) {
         return;
     }
-    if let Some(init_is_empty) = constant_is_empty(cx, init_expr) {
+    if let Some(init_is_empty) = ConstEvalCtxt::new(cx).eval_is_empty(init_expr) {
         span_lint(
             cx,
             CONST_IS_EMPTY,
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
index 05e77386128..33de3b87abc 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
@@ -1,15 +1,12 @@
-#![allow(unused_imports)]
-
 use super::ITER_KV_MAP;
 use clippy_config::msrvs::{self, Msrv};
-use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::source::{snippet, snippet_with_applicability};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::pat_is_wild;
+use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{pat_is_wild, sugg};
-use rustc_hir::{BindingMode, Body, BorrowKind, ByRef, Expr, ExprKind, Mutability, Pat, PatKind};
-use rustc_lint::{LateContext, LintContext};
-use rustc_middle::ty;
-use rustc_span::{sym, Span};
+use rustc_hir::{Body, Expr, ExprKind, PatKind};
+use rustc_lint::LateContext;
+use rustc_span::sym;
 
 /// lint use of:
 ///
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs b/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs
index 262a57ab591..9ff6eaa3487 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::{is_lang_item_or_ctor, is_trait_method};
@@ -14,7 +14,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
     if let OwnerNode::Item(item) = cx.tcx.hir_owner_node(cx.tcx.hir().get_parent_item(expr.hir_id))
         && let def_id = item.owner_id.to_def_id()
         && is_trait_method(cx, expr, sym::Iterator)
-        && let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), arg)
+        && let Some(Constant::Int(0)) = ConstEvalCtxt::new(cx).eval(arg)
         && !is_lang_item_or_ctor(cx, def_id, LangItem::IteratorNext)
     {
         let mut app = Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_skip_zero.rs b/src/tools/clippy/clippy_lints/src/methods/iter_skip_zero.rs
index 6b696b42a69..39e440e784f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_skip_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_skip_zero.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::{is_from_proc_macro, is_trait_method};
 use rustc_errors::Applicability;
@@ -11,7 +11,7 @@ use super::ITER_SKIP_ZERO;
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg_expr: &Expr<'_>) {
     if !expr.span.from_expansion()
         && is_trait_method(cx, expr, sym::Iterator)
-        && let Some(arg) = constant(cx, cx.typeck_results(), arg_expr).and_then(|constant| {
+        && let Some(arg) = ConstEvalCtxt::new(cx).eval(arg_expr).and_then(|constant| {
             if let Constant::Int(arg) = constant {
                 Some(arg)
             } else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs b/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs
index b631cd00cda..9b358235a40 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::is_trait_method;
 use rustc_hir as hir;
@@ -9,7 +9,7 @@ use super::ITERATOR_STEP_BY_ZERO;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, arg: &'tcx hir::Expr<'_>) {
     if is_trait_method(cx, expr, sym::Iterator) {
-        if let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), arg) {
+        if let Some(Constant::Int(0)) = ConstEvalCtxt::new(cx).eval(arg) {
             span_lint(
                 cx,
                 ITERATOR_STEP_BY_ZERO,
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
index a5ba5e5d891..08ce7e204dd 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
@@ -2,10 +2,10 @@ use clippy_config::msrvs::{self, Msrv};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::{is_copy, is_type_diagnostic_item, should_call_clone_as_function};
-use clippy_utils::{is_diag_trait_item, match_def_path, paths, peel_blocks};
+use clippy_utils::{is_diag_trait_item, peel_blocks};
 use rustc_errors::Applicability;
-use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_hir::{self as hir, LangItem};
 use rustc_lint::LateContext;
 use rustc_middle::mir::Mutability;
 use rustc_middle::ty;
@@ -114,7 +114,7 @@ fn handle_path(
     recv: &hir::Expr<'_>,
 ) {
     if let Some(path_def_id) = cx.qpath_res(qpath, arg.hir_id).opt_def_id()
-        && match_def_path(cx, path_def_id, &paths::CLONE_TRAIT_METHOD)
+        && cx.tcx.lang_items().get(LangItem::CloneFn) == Some(path_def_id)
     {
         // The `copied` and `cloned` methods are only available on `&T` and `&mut T` in `Option`
         // and `Result`.
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs b/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs
index fbb83c8ce56..162f0ac564d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_hir::{CaptureBy, Closure, Expr, ExprKind, PatKind};
 use rustc_lint::LateContext;
@@ -22,13 +22,17 @@ pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, arg: &Expr<'_>) {
     {
         // span the area of the closure capture and warn that the
         // original error will be thrown away
-        span_lint_and_help(
+        #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+        span_lint_and_then(
             cx,
             MAP_ERR_IGNORE,
             fn_decl_span,
             "`map_err(|_|...` wildcard pattern discards the original error",
-            None,
-            "consider storing the original error as a source in the new error, or silence this warning using an ignored identifier (`.map_err(|_foo| ...`)",
+            |diag| {
+                diag.help(
+                    "consider storing the original error as a source in the new error, or silence this warning using an ignored identifier (`.map_err(|_foo| ...`)",
+                );
+            },
         );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index aa4cad9342a..1d7b10fe8f0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -133,7 +133,7 @@ mod zst_offset;
 
 use clippy_config::msrvs::{self, Msrv};
 use clippy_config::Conf;
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::macros::FormatArgsStorage;
 use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item};
@@ -749,7 +749,6 @@ declare_clippy_lint! {
     ///
      /// ### Example
     /// ```no_run
-    /// # #![allow(unused)]
     /// (0_i32..10)
     ///     .filter(|n| n.checked_add(1).is_some())
     ///     .map(|n| n.checked_add(1).unwrap());
@@ -757,7 +756,6 @@ declare_clippy_lint! {
     ///
     /// Use instead:
     /// ```no_run
-    /// # #[allow(unused)]
     /// (0_i32..10).filter_map(|n| n.checked_add(1));
     /// ```
     #[clippy::version = "1.51.0"]
@@ -850,7 +848,6 @@ declare_clippy_lint! {
     ///
     /// ### Example
     /// ```no_run
-    /// # #![allow(unused)]
     /// let vec = vec![1];
     /// vec.iter().find(|x| **x == 0).is_some();
     ///
@@ -862,7 +859,6 @@ declare_clippy_lint! {
     /// let vec = vec![1];
     /// vec.iter().any(|x| *x == 0);
     ///
-    /// # #[allow(unused)]
     /// !"hello world".contains("world");
     /// ```
     #[clippy::version = "pre 1.29.0"]
@@ -1505,7 +1501,6 @@ declare_clippy_lint! {
     ///
     /// ### Example
     /// ```no_run
-    /// # #[allow(unused)]
     /// (0..3).fold(false, |acc, x| acc || x > 2);
     /// ```
     ///
@@ -1897,7 +1892,9 @@ declare_clippy_lint! {
     /// trait.
     ///
     /// ### Why is this bad?
-    /// It is recommended style to use collect. See
+    /// If it's needed to create a collection from the contents of an iterator, the `Iterator::collect(_)`
+    /// method is preferred. However, when it's needed to specify the container type,
+    /// `Vec::from_iter(_)` can be more readable than using a turbofish (e.g. `_.collect::<Vec<_>>()`). See
     /// [FromIterator documentation](https://doc.rust-lang.org/std/iter/trait.FromIterator.html)
     ///
     /// ### Example
@@ -1916,6 +1913,14 @@ declare_clippy_lint! {
     ///
     /// assert_eq!(v, vec![5, 5, 5, 5, 5]);
     /// ```
+    /// but prefer to use
+    /// ```no_run
+    /// let numbers: Vec<i32> = FromIterator::from_iter(1..=5);
+    /// ```
+    /// instead of
+    /// ```no_run
+    /// let numbers = (1..=5).collect::<Vec<_>>();
+    /// ```
     #[clippy::version = "1.49.0"]
     pub FROM_ITER_INSTEAD_OF_COLLECT,
     pedantic,
@@ -2008,13 +2013,11 @@ declare_clippy_lint! {
     ///
     /// ### Example
     /// ```no_run
-    /// # #[allow(unused)]
     /// "Hello".bytes().nth(3);
     /// ```
     ///
     /// Use instead:
     /// ```no_run
-    /// # #[allow(unused)]
     /// "Hello".as_bytes().get(3);
     /// ```
     #[clippy::version = "1.52.0"]
@@ -2059,7 +2062,6 @@ declare_clippy_lint! {
     ///
     /// ### Example
     /// ```no_run
-    /// # #![allow(unused)]
     /// let some_vec = vec![0, 1, 2, 3];
     ///
     /// some_vec.iter().count();
@@ -3656,7 +3658,6 @@ declare_clippy_lint! {
     ///
     /// ### Example
     /// ```no_run
-    /// # #![allow(unused)]
     /// let owned_string = "This is a string".to_owned();
     /// owned_string.as_str().as_bytes()
     /// # ;
@@ -3664,7 +3665,6 @@ declare_clippy_lint! {
     ///
     /// Use instead:
     /// ```no_run
-    /// # #![allow(unused)]
     /// let owned_string = "This is a string".to_owned();
     /// owned_string.as_bytes()
     /// # ;
@@ -4915,13 +4915,13 @@ impl Methods {
                     str_split::check(cx, expr, recv, arg);
                 },
                 ("splitn" | "rsplitn", [count_arg, pat_arg]) => {
-                    if let Some(Constant::Int(count)) = constant(cx, cx.typeck_results(), count_arg) {
+                    if let Some(Constant::Int(count)) = ConstEvalCtxt::new(cx).eval(count_arg) {
                         suspicious_splitn::check(cx, name, expr, recv, count);
                         str_splitn::check(cx, name, expr, recv, pat_arg, count, &self.msrv);
                     }
                 },
                 ("splitn_mut" | "rsplitn_mut", [count_arg, _]) => {
-                    if let Some(Constant::Int(count)) = constant(cx, cx.typeck_results(), count_arg) {
+                    if let Some(Constant::Int(count)) = ConstEvalCtxt::new(cx).eval(count_arg) {
                         suspicious_splitn::check(cx, name, expr, recv, count);
                     }
                 },
diff --git a/src/tools/clippy/clippy_lints/src/methods/open_options.rs b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
index d425b505a76..cbeb48b6cc3 100644
--- a/src/tools/clippy/clippy_lints/src/methods/open_options.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
@@ -151,7 +151,7 @@ fn check_open_options(cx: &LateContext<'_>, settings: &[(OpenOption, Argument, S
                 cx,
                 NONSENSICAL_OPEN_OPTIONS,
                 prev_span,
-                format!("the method `{}` is called more than once", &option),
+                format!("the method `{option}` is called more than once"),
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs b/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs
index bb4cdd2a6fa..7837517ed5d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::is_type_lang_item;
@@ -14,7 +14,7 @@ pub(super) fn check<'tcx>(
     recv: &'tcx Expr<'_>,
     repeat_arg: &'tcx Expr<'_>,
 ) {
-    if constant(cx, cx.typeck_results(), repeat_arg) == Some(Constant::Int(1)) {
+    if ConstEvalCtxt::new(cx).eval(repeat_arg) == Some(Constant::Int(1)) {
         let ty = cx.typeck_results().expr_ty(recv).peel_refs();
         if ty.is_str() {
             span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
index 4f42fb73547..12cabd43cb1 100644
--- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
@@ -1,5 +1,5 @@
 use clippy_config::msrvs::{self, Msrv};
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::usage::local_used_after_expr;
@@ -301,7 +301,7 @@ fn parse_iter_usage<'tcx>(
                     };
                 },
                 ("nth" | "skip", [idx_expr]) if cx.tcx.trait_of_item(did) == Some(iter_id) => {
-                    if let Some(Constant::Int(idx)) = constant(cx, cx.typeck_results(), idx_expr) {
+                    if let Some(Constant::Int(idx)) = ConstEvalCtxt::new(cx).eval(idx_expr) {
                         let span = if name.ident.as_str() == "nth" {
                             e.span
                         } else if let Some((_, Node::Expr(next_expr))) = iter.next()
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs
index 78851d4122f..86c0a6322b6 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs
@@ -3,7 +3,7 @@ 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::consts::{ConstEvalCtxt, Constant, ConstantSource, FullInt};
 use clippy_utils::source::snippet;
 
 use rustc_errors::Applicability;
@@ -20,10 +20,9 @@ pub(super) fn check<'tcx>(
     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 ecx = ConstEvalCtxt::with_env(cx.tcx, cx.param_env, typeck_results);
+    if let Some((left, ConstantSource::Local | ConstantSource::CoreConstant)) = ecx.eval_with_source(recv)
+        && let Some((right, ConstantSource::Local | ConstantSource::CoreConstant)) = ecx.eval_with_source(arg)
     {
         let Some(ord) = Constant::partial_cmp(cx.tcx, typeck_results.expr_ty(recv), &left, &right) else {
             return;
@@ -78,9 +77,9 @@ enum Extrema {
 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)?;
+    let cv = ConstEvalCtxt::new(cx).eval(expr)?;
 
-    match (cv.int_value(cx, ty)?, ty.kind()) {
+    match (cv.int_value(cx.tcx, 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),
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index 5d899415d77..fed2b128dcf 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -3,12 +3,11 @@ use super::unnecessary_iter_cloned::{self, is_into_iter};
 use clippy_config::msrvs::{self, Msrv};
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::{snippet, snippet_opt};
-use clippy_utils::ty::{
-    get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, is_type_lang_item, peel_mid_ty_refs,
-};
+use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, is_type_lang_item};
 use clippy_utils::visitors::find_all_ret_expressions;
 use clippy_utils::{
-    fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, match_def_path, paths, return_ty,
+    fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, match_def_path, paths, peel_middle_ty_refs,
+    return_ty,
 };
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
@@ -120,8 +119,8 @@ fn check_addr_of_expr(
                 },
             ] = adjustments[..]
         && let receiver_ty = cx.typeck_results().expr_ty(receiver)
-        && let (target_ty, n_target_refs) = peel_mid_ty_refs(*target_ty)
-        && let (receiver_ty, n_receiver_refs) = peel_mid_ty_refs(receiver_ty)
+        && let (target_ty, n_target_refs) = peel_middle_ty_refs(*target_ty)
+        && let (receiver_ty, n_receiver_refs) = peel_middle_ty_refs(receiver_ty)
         // Only flag cases satisfying at least one of the following three conditions:
         // * the referent and receiver types are distinct
         // * the referent/receiver type is a copyable array
@@ -382,7 +381,7 @@ fn check_other_call_arg<'tcx>(
         && let fn_sig = cx.tcx.fn_sig(callee_def_id).instantiate_identity().skip_binder()
         && let Some(i) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == maybe_arg.hir_id)
         && let Some(input) = fn_sig.inputs().get(i)
-        && let (input, n_refs) = peel_mid_ty_refs(*input)
+        && let (input, n_refs) = peel_middle_ty_refs(*input)
         && let (trait_predicates, _) = get_input_traits_and_projections(cx, callee_def_id, input)
         && let Some(sized_def_id) = cx.tcx.lang_items().sized_trait()
         && let [trait_predicate] = trait_predicates
diff --git a/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs b/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs
index 8b8a965b9f0..3004d9c4233 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_hir_and_then};
+use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::source::{snippet, snippet_opt};
 use clippy_utils::{expr_or_init, is_trait_method, pat_is_wild};
 use rustc_errors::Applicability;
@@ -97,10 +97,8 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>,
             enumerate_span,
             "you seem to use `.enumerate()` and immediately discard the index",
             |diag| {
-                multispan_sugg_with_applicability(
-                    diag,
+                diag.multipart_suggestion(
                     "remove the `.enumerate()` call",
-                    Applicability::MachineApplicable,
                     vec![
                         (closure_param.span, new_closure_param),
                         (
@@ -108,6 +106,7 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>,
                             String::new(),
                         ),
                     ],
+                    Applicability::MachineApplicable,
                 );
             },
         );
diff --git a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
index ae2b6e6347e..ebad4ae6ee9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
@@ -2,10 +2,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::{should_call_clone_as_function, walk_ptrs_ty_depth};
 use clippy_utils::{
-    get_parent_expr, is_diag_trait_item, match_def_path, path_to_local_id, paths, peel_blocks, strip_pat_refs,
+    get_parent_expr, is_diag_trait_item, match_def_path, path_to_local_id, peel_blocks, strip_pat_refs,
 };
 use rustc_errors::Applicability;
-use rustc_hir as hir;
+use rustc_hir::{self as hir, LangItem};
 use rustc_lint::LateContext;
 use rustc_middle::ty::adjustment::Adjust;
 use rustc_middle::ty::{Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
@@ -104,7 +104,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str,
 fn check_qpath(cx: &LateContext<'_>, qpath: hir::QPath<'_>, hir_id: hir::HirId) -> bool {
     // We check it's calling the `clone` method of the `Clone` trait.
     if let Some(path_def_id) = cx.qpath_res(&qpath, hir_id).opt_def_id() {
-        match_def_path(cx, path_def_id, &paths::CLONE_TRAIT_METHOD)
+        cx.tcx.lang_items().get(LangItem::CloneFn) == Some(path_def_id)
     } else {
         false
     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/verbose_file_reads.rs b/src/tools/clippy/clippy_lints/src/methods/verbose_file_reads.rs
index 181b413a182..8ed61637eca 100644
--- a/src/tools/clippy/clippy_lints/src/methods/verbose_file_reads.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/verbose_file_reads.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_trait_method;
 use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_hir::{Expr, ExprKind, QPath};
@@ -23,6 +23,9 @@ pub(super) fn check<'tcx>(
         && matches!(recv.kind, ExprKind::Path(QPath::Resolved(None, _)))
         && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(recv).peel_refs(), sym::File)
     {
-        span_lint_and_help(cx, VERBOSE_FILE_READS, expr.span, msg, None, help);
+        #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+        span_lint_and_then(cx, VERBOSE_FILE_READS, expr.span, msg, |diag| {
+            diag.help(help);
+        });
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
index 28068c63473..7384e534ed7 100644
--- a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
@@ -127,7 +127,7 @@ pub(super) fn check<'tcx>(
                         .collect::<Vec<_>>()
                         .join(" and ");
 
-                    format!("methods with the following characteristics: ({})", &s)
+                    format!("methods with the following characteristics: ({s})")
                 } else {
                     format!("methods called {}", &conventions[0])
                 }
diff --git a/src/tools/clippy/clippy_lints/src/minmax.rs b/src/tools/clippy/clippy_lints/src/minmax.rs
index c3fbca1d560..e95864c6db8 100644
--- a/src/tools/clippy/clippy_lints/src/minmax.rs
+++ b/src/tools/clippy/clippy_lints/src/minmax.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant_simple, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::is_trait_method;
 use rustc_hir::{Expr, ExprKind};
@@ -106,15 +106,11 @@ fn fetch_const<'a, 'tcx>(
     if args.next().is_some() {
         return None;
     }
-    constant_simple(cx, cx.typeck_results(), first_arg).map_or_else(
-        || constant_simple(cx, cx.typeck_results(), second_arg).map(|c| (m, c, first_arg)),
-        |c| {
-            if constant_simple(cx, cx.typeck_results(), second_arg).is_none() {
-                // otherwise ignore
-                Some((m, c, second_arg))
-            } else {
-                None
-            }
-        },
-    )
+    let ecx = ConstEvalCtxt::new(cx);
+    match (ecx.eval_simple(first_arg), ecx.eval_simple(second_arg)) {
+        (Some(c), None) => Some((m, c, second_arg)),
+        (None, Some(c)) => Some((m, c, first_arg)),
+        // otherwise ignore
+        _ => None,
+    }
 }
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs b/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs
index e0a5e401a50..22467999cd8 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_errors::Applicability;
 use rustc_lint::EarlyContext;
 use rustc_span::Span;
@@ -12,24 +12,36 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit_span: Span, lit_snip: &str, suffi
     // Do not lint when literal is unsuffixed.
     if !suffix.is_empty() {
         if lit_snip.as_bytes()[maybe_last_sep_idx] == b'_' {
-            span_lint_and_sugg(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 SEPARATED_LITERAL_SUFFIX,
                 lit_span,
                 format!("{sugg_type} type suffix should not be separated by an underscore"),
-                "remove the underscore",
-                format!("{}{suffix}", &lit_snip[..maybe_last_sep_idx]),
-                Applicability::MachineApplicable,
+                |diag| {
+                    diag.span_suggestion(
+                        lit_span,
+                        "remove the underscore",
+                        format!("{}{suffix}", &lit_snip[..maybe_last_sep_idx]),
+                        Applicability::MachineApplicable,
+                    );
+                },
             );
         } else {
-            span_lint_and_sugg(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 UNSEPARATED_LITERAL_SUFFIX,
                 lit_span,
                 format!("{sugg_type} type suffix should be separated by an underscore"),
-                "add an underscore",
-                format!("{}_{suffix}", &lit_snip[..=maybe_last_sep_idx]),
-                Applicability::MachineApplicable,
+                |diag| {
+                    diag.span_suggestion(
+                        lit_span,
+                        "add an underscore",
+                        format!("{}_{suffix}", &lit_snip[..=maybe_last_sep_idx]),
+                        Applicability::MachineApplicable,
+                    );
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs b/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs
index cb305cf5582..6db03adf44a 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
+use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::source::snippet_opt;
 use rustc_ast::ast::{Pat, PatKind};
 use rustc_lint::EarlyContext;
@@ -21,13 +21,15 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
             }
         }
         if !pfields.is_empty() && wilds == pfields.len() {
-            span_lint_and_help(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 UNNEEDED_FIELD_PATTERN,
                 pat.span,
                 "all the struct fields are matched to a wildcard pattern, consider using `..`",
-                None,
-                format!("try with `{type_name} {{ .. }}` instead"),
+                |diag| {
+                    diag.help(format!("try with `{type_name} {{ .. }}` instead"));
+                },
             );
             return;
         }
@@ -56,14 +58,15 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
                             }
                         }
 
-                        span_lint_and_help(
+                        #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+                        span_lint_and_then(
                             cx,
                             UNNEEDED_FIELD_PATTERN,
                             field.span,
-                            "you matched a field with a wildcard pattern, consider using `..` \
-                             instead",
-                            None,
-                            format!("try with `{type_name} {{ {}, .. }}`", normal[..].join(", ")),
+                            "you matched a field with a wildcard pattern, consider using `..` instead",
+                            |diag| {
+                                diag.help(format!("try with `{type_name} {{ {}, .. }}`", normal[..].join(", ")));
+                            },
                         );
                     }
                 }
diff --git a/src/tools/clippy/clippy_lints/src/missing_assert_message.rs b/src/tools/clippy/clippy_lints/src/missing_assert_message.rs
index 935ed48dacc..a9ea11f4c2b 100644
--- a/src/tools/clippy/clippy_lints/src/missing_assert_message.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_assert_message.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_in_test;
 use clippy_utils::macros::{find_assert_args, find_assert_eq_args, root_macro_call_first_node, PanicExpn};
 use rustc_hir::Expr;
@@ -79,13 +79,15 @@ impl<'tcx> LateLintPass<'tcx> for MissingAssertMessage {
         };
 
         if let PanicExpn::Empty = panic_expn {
-            span_lint_and_help(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 MISSING_ASSERT_MESSAGE,
                 macro_call.span,
                 "assert without any message",
-                None,
-                "consider describing why the failing assert is problematic",
+                |diag| {
+                    diag.help("consider describing why the failing assert is problematic");
+                },
             );
         }
     }
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 68c158330ab..052d738b2e7 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
@@ -186,7 +186,7 @@ fn already_const(header: hir::FnHeader) -> bool {
 fn could_be_const_with_abi(cx: &LateContext<'_>, msrv: &Msrv, abi: Abi) -> bool {
     match abi {
         Abi::Rust => true,
-        // `const extern "C"` was stablized after 1.62.0
+        // `const extern "C"` was stabilized after 1.62.0
         Abi::C { unwind: false } => msrv.meets(msrvs::CONST_EXTERN_FN),
         // Rest ABIs are still unstable and need the `const_extern_fn` feature enabled.
         _ => cx.tcx.features().const_extern_fn,
diff --git a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
index 85029a5e6a0..7ee746365d1 100644
--- a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
@@ -1,10 +1,9 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_lint_allowed;
 use clippy_utils::macros::span_is_local;
-use rustc_hir::def_id::DefIdMap;
+use rustc_hir::def_id::DefIdSet;
 use rustc_hir::{Impl, Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::AssocItem;
 use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
@@ -68,33 +67,26 @@ impl<'tcx> LateLintPass<'tcx> for MissingTraitMethods {
             }) = item.kind
             && let Some(trait_id) = trait_ref.trait_def_id()
         {
-            let mut provided: DefIdMap<&AssocItem> = cx
-                .tcx
-                .provided_trait_methods(trait_id)
-                .map(|assoc| (assoc.def_id, assoc))
+            let trait_item_ids: DefIdSet = items
+                .iter()
+                .filter_map(|impl_item| impl_item.trait_item_def_id)
                 .collect();
 
-            for impl_item in *items {
-                if let Some(def_id) = impl_item.trait_item_def_id {
-                    provided.remove(&def_id);
-                }
+            for assoc in cx
+                .tcx
+                .provided_trait_methods(trait_id)
+                .filter(|assoc| !trait_item_ids.contains(&assoc.def_id))
+            {
+                span_lint_and_then(
+                    cx,
+                    MISSING_TRAIT_METHODS,
+                    cx.tcx.def_span(item.owner_id),
+                    format!("missing trait method provided by default: `{}`", assoc.name),
+                    |diag| {
+                        diag.span_help(cx.tcx.def_span(assoc.def_id), "implement the method");
+                    },
+                );
             }
-
-            cx.tcx.with_stable_hashing_context(|hcx| {
-                for assoc in provided.values_sorted(&hcx, true) {
-                    let source_map = cx.tcx.sess.source_map();
-                    let definition_span = source_map.guess_head_span(cx.tcx.def_span(assoc.def_id));
-
-                    span_lint_and_help(
-                        cx,
-                        MISSING_TRAIT_METHODS,
-                        source_map.guess_head_span(item.span),
-                        format!("missing trait method provided by default: `{}`", assoc.name),
-                        Some(definition_span),
-                        "implement the method",
-                    );
-                }
-            });
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
index 9c5a8a0cfcd..6964d8c8dbb 100644
--- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
+++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::{span_lint, span_lint_and_note};
+use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id};
 use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, LetStmt, Node, Stmt, StmtKind};
@@ -324,13 +324,17 @@ impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> {
         if path_to_local_id(expr, self.var) {
             // Check that this is a read, not a write.
             if !is_in_assignment_position(self.cx, expr) {
-                span_lint_and_note(
+                span_lint_and_then(
                     self.cx,
                     MIXED_READ_WRITE_IN_EXPRESSION,
                     expr.span,
                     format!("unsequenced read of `{}`", self.cx.tcx.hir().name(self.var)),
-                    Some(self.write_expr.span),
-                    "whether read occurs before this write depends on evaluation order",
+                    |diag| {
+                        diag.span_note(
+                            self.write_expr.span,
+                            "whether read occurs before this write depends on evaluation order",
+                        );
+                    },
                 );
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/module_style.rs b/src/tools/clippy/clippy_lints/src/module_style.rs
index 305499f9da4..e9c5f64a255 100644
--- a/src/tools/clippy/clippy_lints/src/module_style.rs
+++ b/src/tools/clippy/clippy_lints/src/module_style.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_ast::ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext};
@@ -121,17 +121,18 @@ impl EarlyLintPass for ModStyle {
         for folder in &folder_segments {
             if !mod_folders.contains(folder) {
                 if let Some((file, path)) = file_map.get(folder) {
-                    let mut correct = path.to_path_buf();
-                    correct.pop();
-                    correct.push(folder);
-                    correct.push("mod.rs");
-                    span_lint_and_help(
+                    span_lint_and_then(
                         cx,
                         SELF_NAMED_MODULE_FILES,
                         Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None),
                         format!("`mod.rs` files are required, found `{}`", path.display()),
-                        None,
-                        format!("move `{}` to `{}`", path.display(), correct.display(),),
+                        |diag| {
+                            let mut correct = path.to_path_buf();
+                            correct.pop();
+                            correct.push(folder);
+                            correct.push("mod.rs");
+                            diag.help(format!("move `{}` to `{}`", path.display(), correct.display(),));
+                        },
                     );
                 }
             }
@@ -161,17 +162,18 @@ fn process_paths_for_mod_files<'a>(
 /// for code-sharing between tests.
 fn check_self_named_mod_exists(cx: &EarlyContext<'_>, path: &Path, file: &SourceFile) {
     if path.ends_with("mod.rs") && !path.starts_with("tests") {
-        let mut mod_file = path.to_path_buf();
-        mod_file.pop();
-        mod_file.set_extension("rs");
-
-        span_lint_and_help(
+        span_lint_and_then(
             cx,
             MOD_MODULE_FILES,
             Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None),
             format!("`mod.rs` files are not allowed, found `{}`", path.display()),
-            None,
-            format!("move `{}` to `{}`", path.display(), mod_file.display()),
+            |diag| {
+                let mut mod_file = path.to_path_buf();
+                mod_file.pop();
+                mod_file.set_extension("rs");
+
+                diag.help(format!("move `{}` to `{}`", path.display(), mod_file.display()));
+            },
         );
     }
 }
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 67f9b52c352..32e7fde03b2 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
@@ -1,7 +1,7 @@
 use clippy_config::msrvs::{self, Msrv};
 use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::mir::PossibleBorrowerMap;
+use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exactly_once, PossibleBorrowerMap};
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::{implements_trait, is_copy};
 use clippy_utils::{expr_use_ctxt, peel_n_hir_expr_refs, DefinedTy, ExprUseNode};
@@ -12,6 +12,7 @@ use rustc_hir::{Body, Expr, ExprKind, Mutability, Path, QPath};
 use rustc_index::bit_set::BitSet;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::mir::{Rvalue, StatementKind};
 use rustc_middle::ty::{
     self, ClauseKind, EarlyBinder, FnSig, GenericArg, GenericArgKind, ParamTy, ProjectionPredicate, Ty,
 };
@@ -107,6 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> {
             }
             && let count = needless_borrow_count(
                 cx,
+                &mut self.possible_borrowers,
                 fn_id,
                 cx.typeck_results().node_args(hir_id),
                 i,
@@ -155,9 +157,14 @@ fn path_has_args(p: &QPath<'_>) -> bool {
 /// The following constraints will be checked:
 /// * The borrowed expression meets all the generic type's constraints.
 /// * The generic type appears only once in the functions signature.
-/// * The borrowed value is Copy itself OR not a variable (created by a function call)
+/// * The borrowed value is:
+///   - `Copy` itself, or
+///   - the only use of a mutable reference, or
+///   - not a variable (created by a function call)
+#[expect(clippy::too_many_arguments)]
 fn needless_borrow_count<'tcx>(
     cx: &LateContext<'tcx>,
+    possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
     fn_id: DefId,
     callee_args: ty::GenericArgsRef<'tcx>,
     arg_index: usize,
@@ -232,9 +239,9 @@ fn needless_borrow_count<'tcx>(
 
         let referent_ty = cx.typeck_results().expr_ty(referent);
 
-        if (!is_copy(cx, referent_ty) && !referent_ty.is_ref())
-            && let ExprKind::AddrOf(_, _, inner) = reference.kind
-            && !matches!(inner.kind, ExprKind::Call(..) | ExprKind::MethodCall(..))
+        if !(is_copy(cx, referent_ty)
+            || referent_ty.is_ref() && referent_used_exactly_once(cx, possible_borrowers, reference)
+            || matches!(referent.kind, ExprKind::Call(..) | ExprKind::MethodCall(..)))
         {
             return false;
         }
@@ -337,6 +344,37 @@ fn is_mixed_projection_predicate<'tcx>(
     }
 }
 
+fn referent_used_exactly_once<'tcx>(
+    cx: &LateContext<'tcx>,
+    possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
+    reference: &Expr<'tcx>,
+) -> bool {
+    if let Some(mir) = enclosing_mir(cx.tcx, reference.hir_id)
+        && let Some(local) = expr_local(cx.tcx, reference)
+        && let [location] = *local_assignments(mir, local).as_slice()
+        && let block_data = &mir.basic_blocks[location.block]
+        && let Some(statement) = block_data.statements.get(location.statement_index)
+        && let StatementKind::Assign(box (_, Rvalue::Ref(_, _, place))) = statement.kind
+        && !place.is_indirect_first_projection()
+    {
+        let body_owner_local_def_id = cx.tcx.hir().enclosing_body_owner(reference.hir_id);
+        if possible_borrowers
+            .last()
+            .map_or(true, |&(local_def_id, _)| local_def_id != body_owner_local_def_id)
+        {
+            possible_borrowers.push((body_owner_local_def_id, PossibleBorrowerMap::new(cx, mir)));
+        }
+        let possible_borrower = &mut possible_borrowers.last_mut().unwrap().1;
+        // If `only_borrowers` were used here, the `copyable_iterator::warn` test would fail. The reason is
+        // that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible borrower of
+        // itself. See the comment in that method for an explanation as to why.
+        possible_borrower.bounded_borrowers(&[local], &[local, place.local], place.local, location)
+            && used_exactly_once(mir, place.local).unwrap_or(false)
+    } else {
+        false
+    }
+}
+
 // Iteratively replaces `param_ty` with `new_ty` in `args`, and similarly for each resulting
 // projected type that is a type parameter. Returns `false` if replacing the types would have an
 // effect on the function signature beyond substituting `new_ty` for `param_ty`.
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index f2e00cef7e9..a0bbf6b14b2 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_self;
 use clippy_utils::ptr::get_spans;
 use clippy_utils::source::{snippet, snippet_opt};
@@ -278,9 +278,12 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
                         }
                     }
 
-                    let spans = vec![(input.span, format!("&{}", snippet(cx, input.span, "_")))];
-
-                    multispan_sugg(diag, "consider taking a reference instead", spans);
+                    diag.span_suggestion(
+                        input.span,
+                        "consider taking a reference instead",
+                        format!("&{}", snippet(cx, input.span, "_")),
+                        Applicability::MaybeIncorrect,
+                    );
                 };
 
                 span_lint_and_then(
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index 9d326c06eff..8232e69db39 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -273,7 +273,7 @@ fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
             }
             let snippet =
                 if let (Some(arr), Some(func)) = (snippet_opt(cx, reduced[0].span), snippet_opt(cx, reduced[1].span)) {
-                    format!("assert!({}.len() > {});", &arr, &func)
+                    format!("assert!({arr}.len() > {func});")
                 } else {
                     return;
                 };
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 15bb328b446..6915cd40615 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -6,7 +6,7 @@ use std::ptr;
 
 use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::in_constant;
+use clippy_utils::is_in_const_context;
 use clippy_utils::macros::macro_backtrace;
 use clippy_utils::ty::{implements_trait, InteriorMut};
 use rustc_hir::def::{DefKind, Res};
@@ -406,7 +406,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if let ExprKind::Path(qpath) = &expr.kind {
             // Only lint if we use the const item inside a function.
-            if in_constant(cx, expr.hir_id) {
+            if is_in_const_context(cx) {
                 return;
             }
 
diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
index 8b8aabe7acc..aadd729f32a 100644
--- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
@@ -243,7 +243,6 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
                 owner_id,
                 ..
             }) => {
-                #[allow(trivial_casts)]
                 if let Node::Item(item) = cx.tcx.parent_hir_node(owner_id.into())
                     && let Some(trait_ref) = cx
                         .tcx
diff --git a/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs b/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs
index 9769da6d3e9..a0de5ea711c 100644
--- a/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs
@@ -3,7 +3,7 @@ use rustc_lint::LateContext;
 use rustc_middle::ty;
 
 use clippy_utils::comparisons::{normalize_comparison, Rel};
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::is_isize_or_usize;
@@ -121,7 +121,7 @@ fn detect_absurd_comparison<'tcx>(
 fn detect_extreme_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<ExtremeExpr<'tcx>> {
     let ty = cx.typeck_results().expr_ty(expr);
 
-    let cv = constant(cx, cx.typeck_results(), expr)?;
+    let cv = ConstEvalCtxt::new(cx).eval(expr)?;
 
     let which = match (ty.kind(), cv) {
         (&ty::Bool, Constant::Bool(false)) | (&ty::Uint(_), Constant::Int(0)) => ExtremeType::Minimum,
diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
index a7e381be743..bc71a4790b9 100644
--- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -1,6 +1,6 @@
 use super::ARITHMETIC_SIDE_EFFECTS;
 use clippy_config::Conf;
-use clippy_utils::consts::{constant, constant_simple, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{expr_or_init, is_from_proc_macro, is_lint_allowed, peel_hir_expr_refs, peel_hir_expr_unary};
@@ -162,7 +162,7 @@ impl ArithmeticSideEffects {
         {
             return Some(n.get());
         }
-        if let Some(Constant::Int(n)) = constant(cx, cx.typeck_results(), expr) {
+        if let Some(Constant::Int(n)) = ConstEvalCtxt::new(cx).eval(expr) {
             return Some(n);
         }
         None
@@ -200,7 +200,7 @@ impl ArithmeticSideEffects {
         lhs: &'tcx hir::Expr<'_>,
         rhs: &'tcx hir::Expr<'_>,
     ) {
-        if constant_simple(cx, cx.typeck_results(), expr).is_some() {
+        if ConstEvalCtxt::new(cx).eval_simple(expr).is_some() {
             return;
         }
         if !matches!(
@@ -280,7 +280,7 @@ impl ArithmeticSideEffects {
         let Some(arg) = args.first() else {
             return;
         };
-        if constant_simple(cx, cx.typeck_results(), receiver).is_some() {
+        if ConstEvalCtxt::new(cx).eval_simple(receiver).is_some() {
             return;
         }
         let instance_ty = cx.typeck_results().expr_ty(receiver);
@@ -308,7 +308,7 @@ impl ArithmeticSideEffects {
         let hir::UnOp::Neg = un_op else {
             return;
         };
-        if constant(cx, cx.typeck_results(), un_expr).is_some() {
+        if ConstEvalCtxt::new(cx).eval(un_expr).is_some() {
             return;
         }
         let ty = cx.typeck_results().expr_ty(expr).peel_refs();
diff --git a/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs
index 545e680ce0d..4414056a467 100644
--- a/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::LateContext;
@@ -166,7 +166,7 @@ fn check_ineffective_gt(cx: &LateContext<'_>, span: Span, m: u128, c: u128, op:
 }
 
 fn fetch_int_literal(cx: &LateContext<'_>, lit: &Expr<'_>) -> Option<u128> {
-    match constant(cx, cx.typeck_results(), lit)? {
+    match ConstEvalCtxt::new(cx).eval(lit)? {
         Constant::Int(n) => Some(n),
         _ => None,
     }
diff --git a/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs b/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs
index 7bf9b8ef866..c1317524396 100644
--- a/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs
@@ -2,7 +2,7 @@
 
 use std::cmp::Ordering;
 
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::layout::HasTyCtxt;
@@ -20,13 +20,14 @@ use super::{IMPOSSIBLE_COMPARISONS, REDUNDANT_COMPARISONS};
 // Flip yoda conditionals, turnings expressions like `42 < x` into `x > 42`
 fn comparison_to_const<'tcx>(
     cx: &LateContext<'tcx>,
-    typeck: &TypeckResults<'tcx>,
+    typeck: &'tcx TypeckResults<'tcx>,
     expr: &'tcx Expr<'tcx>,
 ) -> Option<(CmpOp, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>, Constant<'tcx>, Ty<'tcx>)> {
     if let ExprKind::Binary(operator, left, right) = expr.kind
         && let Ok(cmp_op) = CmpOp::try_from(operator.node)
     {
-        match (constant(cx, typeck, left), constant(cx, typeck, right)) {
+        let ecx = ConstEvalCtxt::with_env(cx.tcx, cx.param_env, typeck);
+        match (ecx.eval(left), ecx.eval(right)) {
             (Some(_), Some(_)) => None,
             (_, Some(con)) => Some((cmp_op, left, right, con, typeck.expr_ty(right))),
             (Some(con), _) => Some((cmp_op.reverse(), right, left, con, typeck.expr_ty(left))),
diff --git a/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs b/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs
index ca3112ce5c4..e3029f8438e 100644
--- a/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::is_type_diagnostic_item;
@@ -19,7 +19,7 @@ pub(crate) fn check<'tcx>(
     if op == BinOpKind::Div
         && let ExprKind::MethodCall(method_path, self_arg, [], _) = left.kind
         && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_arg).peel_refs(), sym::Duration)
-        && let Some(Constant::Int(divisor)) = constant(cx, cx.typeck_results(), right)
+        && let Some(Constant::Int(divisor)) = ConstEvalCtxt::new(cx).eval(right)
     {
         let suggested_fn = match (method_path.ident.as_str(), divisor) {
             ("subsec_micros", 1_000) | ("subsec_nanos", 1_000_000) => "subsec_millis",
diff --git a/src/tools/clippy/clippy_lints/src/operators/erasing_op.rs b/src/tools/clippy/clippy_lints/src/operators/erasing_op.rs
index 066e08f3bd4..24bfe2b050b 100644
--- a/src/tools/clippy/clippy_lints/src/operators/erasing_op.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/erasing_op.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant_simple, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::ty::same_type_and_consts;
 
@@ -34,12 +34,12 @@ fn different_types(tck: &TypeckResults<'_>, input: &Expr<'_>, output: &Expr<'_>)
 
 fn check_op<'tcx>(
     cx: &LateContext<'tcx>,
-    tck: &TypeckResults<'tcx>,
+    tck: &'tcx TypeckResults<'tcx>,
     op: &Expr<'tcx>,
     other: &Expr<'tcx>,
     parent: &Expr<'tcx>,
 ) {
-    if constant_simple(cx, tck, op) == Some(Constant::Int(0)) {
+    if ConstEvalCtxt::with_env(cx.tcx, cx.param_env, tck).eval_simple(op) == Some(Constant::Int(0)) {
         if different_types(tck, other, parent) {
             return;
         }
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 0e5b440c50f..df6e6745596 100644
--- a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant_with_source, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::get_item_name;
 use clippy_utils::sugg::Sugg;
@@ -17,12 +17,14 @@ pub(crate) fn check<'tcx>(
     right: &'tcx Expr<'_>,
 ) {
     if (op == BinOpKind::Eq || op == BinOpKind::Ne) && is_float(cx, left) {
-        let left_is_local = match constant_with_source(cx, cx.typeck_results(), left) {
+        let typeck = cx.typeck_results();
+        let ecx = ConstEvalCtxt::with_env(cx.tcx, cx.param_env, typeck);
+        let left_is_local = match ecx.eval_with_source(left) {
             Some((c, s)) if !is_allowed(&c) => s.is_local(),
             Some(_) => return,
             None => true,
         };
-        let right_is_local = match constant_with_source(cx, cx.typeck_results(), right) {
+        let right_is_local = match ecx.eval_with_source(right) {
             Some((c, s)) if !is_allowed(&c) => s.is_local(),
             Some(_) => return,
             None => true,
diff --git a/src/tools/clippy/clippy_lints/src/operators/identity_op.rs b/src/tools/clippy/clippy_lints/src/operators/identity_op.rs
index 0879dcd9bcd..830be50c8ba 100644
--- a/src/tools/clippy/clippy_lints/src/operators/identity_op.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/identity_op.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant_full_int, constant_simple, Constant, FullInt};
+use clippy_utils::consts::{ConstEvalCtxt, Constant, FullInt};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::{clip, peel_hir_expr_refs, unsext};
@@ -184,14 +184,13 @@ fn is_allowed(cx: &LateContext<'_>, cmp: BinOpKind, left: &Expr<'_>, right: &Exp
         && cx.typeck_results().expr_ty(right).peel_refs().is_integral()
         // `1 << 0` is a common pattern in bit manipulation code
         && !(cmp == BinOpKind::Shl
-            && constant_simple(cx, cx.typeck_results(), right) == Some(Constant::Int(0))
-            && constant_simple(cx, cx.typeck_results(), left) == Some(Constant::Int(1)))
+            && ConstEvalCtxt::new(cx).eval_simple(right) == Some(Constant::Int(0))
+            && ConstEvalCtxt::new(cx).eval_simple(left) == Some(Constant::Int(1)))
 }
 
 fn check_remainder(cx: &LateContext<'_>, left: &Expr<'_>, right: &Expr<'_>, span: Span, arg: Span) {
-    let lhs_const = constant_full_int(cx, cx.typeck_results(), left);
-    let rhs_const = constant_full_int(cx, cx.typeck_results(), right);
-    if match (lhs_const, rhs_const) {
+    let ecx = ConstEvalCtxt::new(cx);
+    if match (ecx.eval_full_int(left), ecx.eval_full_int(right)) {
         (Some(FullInt::S(lv)), Some(FullInt::S(rv))) => lv.abs() < rv.abs(),
         (Some(FullInt::U(lv)), Some(FullInt::U(rv))) => lv < rv,
         _ => return,
@@ -201,7 +200,7 @@ fn check_remainder(cx: &LateContext<'_>, left: &Expr<'_>, right: &Expr<'_>, span
 }
 
 fn check_op(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span, parens: Parens, is_erased: bool) -> bool {
-    if let Some(Constant::Int(v)) = constant_simple(cx, cx.typeck_results(), e).map(Constant::peel_refs) {
+    if let Some(Constant::Int(v)) = ConstEvalCtxt::new(cx).eval_simple(e).map(Constant::peel_refs) {
         let check = match *cx.typeck_results().expr_ty(e).peel_refs().kind() {
             ty::Int(ity) => unsext(cx.tcx, -1_i128, ity),
             ty::Uint(uty) => clip(cx.tcx, !0, uty),
diff --git a/src/tools/clippy/clippy_lints/src/operators/integer_division.rs b/src/tools/clippy/clippy_lints/src/operators/integer_division.rs
index 631d10f4a72..76eba7327cf 100644
--- a/src/tools/clippy/clippy_lints/src/operators/integer_division.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/integer_division.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
 
@@ -15,13 +15,9 @@ pub(crate) fn check<'tcx>(
         && cx.typeck_results().expr_ty(left).is_integral()
         && cx.typeck_results().expr_ty(right).is_integral()
     {
-        span_lint_and_help(
-            cx,
-            INTEGER_DIVISION,
-            expr.span,
-            "integer division",
-            None,
-            "division of integers may cause loss of precision. consider using floats",
-        );
+        #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+        span_lint_and_then(cx, INTEGER_DIVISION, expr.span, "integer division", |diag| {
+            diag.help("division of integers may cause loss of precision. consider using floats");
+        });
     }
 }
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 d65fffac5a8..c83bdda347a 100644
--- a/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::sext;
 use rustc_hir::{BinOpKind, Expr, ExprKind, Node};
@@ -42,15 +42,11 @@ fn used_in_comparison_with_zero(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     };
 
     if op.node == BinOpKind::Eq || op.node == BinOpKind::Ne {
-        if let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), rhs) {
-            return true;
-        }
-        if let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), lhs) {
-            return true;
-        }
+        let ecx = ConstEvalCtxt::new(cx);
+        matches!(ecx.eval(lhs), Some(Constant::Int(0))) || matches!(ecx.eval(rhs), Some(Constant::Int(0)))
+    } else {
+        false
     }
-
-    false
 }
 
 struct OperandInfo {
@@ -60,7 +56,7 @@ struct OperandInfo {
 }
 
 fn analyze_operand(operand: &Expr<'_>, cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<OperandInfo> {
-    match constant(cx, cx.typeck_results(), operand) {
+    match ConstEvalCtxt::new(cx).eval(operand) {
         Some(Constant::Int(v)) => match *cx.typeck_results().expr_ty(expr).kind() {
             ty::Int(ity) => {
                 let value = sext(cx.tcx, v, ity);
diff --git a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
index ea933168cfd..565294bb40a 100644
--- a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
@@ -1,5 +1,5 @@
 use super::FLOAT_ARITHMETIC;
-use clippy_utils::consts::constant_simple;
+use clippy_utils::consts::ConstEvalCtxt;
 use clippy_utils::diagnostics::span_lint;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -55,7 +55,7 @@ impl Context {
             return;
         }
         let ty = cx.typeck_results().expr_ty(arg);
-        if constant_simple(cx, cx.typeck_results(), expr).is_none() && ty.is_floating_point() {
+        if ConstEvalCtxt::new(cx).eval_simple(expr).is_none() && ty.is_floating_point() {
             span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected");
             self.expr_id = Some(expr.hir_id);
         }
diff --git a/src/tools/clippy/clippy_lints/src/operators/op_ref.rs b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
index c2b27c9b229..82b9d10fbeb 100644
--- a/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::get_enclosing_block;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::{implements_trait, is_copy};
@@ -64,10 +64,10 @@ pub(crate) fn check<'tcx>(
                         |diag| {
                             let lsnip = snippet(cx, l.span, "...").to_string();
                             let rsnip = snippet(cx, r.span, "...").to_string();
-                            multispan_sugg(
-                                diag,
+                            diag.multipart_suggestion(
                                 "use the values directly",
                                 vec![(left.span, lsnip), (right.span, rsnip)],
+                                Applicability::MachineApplicable,
                             );
                         },
                     );
diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
index d4906328ccb..ae02d22512e 100644
--- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
@@ -1,8 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{
-    can_move_expr_to_closure, eager_or_lazy, higher, in_constant, is_else_clause, is_res_lang_ctor, peel_blocks,
-    peel_hir_expr_while, CaptureKind,
+    can_move_expr_to_closure, eager_or_lazy, higher, is_else_clause, is_in_const_context, is_res_lang_ctor,
+    peel_blocks, peel_hir_expr_while, CaptureKind,
 };
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
@@ -294,7 +294,7 @@ fn is_none_or_err_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
 impl<'tcx> LateLintPass<'tcx> for OptionIfLetElse {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
         // Don't lint macros and constants
-        if expr.span.from_expansion() || in_constant(cx, expr.hir_id) {
+        if expr.span.from_expansion() || is_in_const_context(cx) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs b/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs
index 2d20cbea698..267e2067e10 100644
--- a/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs
+++ b/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_ast::ast::{Item, ItemKind};
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::declare_lint_pass;
@@ -57,24 +57,16 @@ impl EarlyLintPass for PartialPubFields {
 
         for field in fields {
             if all_priv && field.vis.kind.is_pub() {
-                span_lint_and_help(
-                    cx,
-                    PARTIAL_PUB_FIELDS,
-                    field.vis.span,
-                    msg,
-                    None,
-                    "consider using private field here",
-                );
+                #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+                span_lint_and_then(cx, PARTIAL_PUB_FIELDS, field.vis.span, msg, |diag| {
+                    diag.help("consider using private field here");
+                });
                 return;
             } else if all_pub && !field.vis.kind.is_pub() {
-                span_lint_and_help(
-                    cx,
-                    PARTIAL_PUB_FIELDS,
-                    field.vis.span,
-                    msg,
-                    None,
-                    "consider using public field here",
-                );
+                #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+                span_lint_and_then(cx, PARTIAL_PUB_FIELDS, field.vis.span, msg, |diag| {
+                    diag.help("consider using public field here");
+                });
                 return;
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs b/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs
index 0008f154ae3..18bfb588a11 100644
--- a/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs
+++ b/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs
@@ -21,8 +21,8 @@ declare_clippy_lint! {
     /// `PathBuf::from` instead.
     ///
     /// ### Known problems
-    /// `.join()` introduces an implicit `clone()`. `PathBuf::from` can alternativly be
-    /// used when the `PathBuf` is newly constructed. This will avoild the implicit clone.
+    /// `.join()` introduces an implicit `clone()`. `PathBuf::from` can alternatively be
+    /// used when the `PathBuf` is newly constructed. This will avoid the implicit clone.
     ///
     /// ### Example
     /// ```rust
diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
index 9661a57b8b9..c1296b04387 100644
--- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
+++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_hir::{
     intravisit, Body, Expr, ExprKind, FnDecl, LetExpr, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind,
 };
@@ -133,23 +133,25 @@ enum DerefPossible {
 fn apply_lint(cx: &LateContext<'_>, pat: &Pat<'_>, deref_possible: DerefPossible) -> bool {
     let maybe_mismatch = find_first_mismatch(cx, pat);
     if let Some((span, mutability, level)) = maybe_mismatch {
-        span_lint_and_help(
+        #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+        span_lint_and_then(
             cx,
             PATTERN_TYPE_MISMATCH,
             span,
             "type of pattern does not match the expression type",
-            None,
-            format!(
-                "{}explicitly match against a `{}` pattern and adjust the enclosed variable bindings",
-                match (deref_possible, level) {
-                    (DerefPossible::Possible, Level::Top) => "use `*` to dereference the match expression or ",
-                    _ => "",
-                },
-                match mutability {
-                    Mutability::Mut => "&mut _",
-                    Mutability::Not => "&_",
-                },
-            ),
+            |diag| {
+                diag.help(format!(
+                    "{}explicitly match against a `{}` pattern and adjust the enclosed variable bindings",
+                    match (deref_possible, level) {
+                        (DerefPossible::Possible, Level::Top) => "use `*` to dereference the match expression or ",
+                        _ => "",
+                    },
+                    match mutability {
+                        Mutability::Mut => "&mut _",
+                        Mutability::Not => "&_",
+                    },
+                ));
+            },
         );
         true
     } else {
diff --git a/src/tools/clippy/clippy_lints/src/pub_use.rs b/src/tools/clippy/clippy_lints/src/pub_use.rs
index ab8f8a1689d..5b973a79eae 100644
--- a/src/tools/clippy/clippy_lints/src/pub_use.rs
+++ b/src/tools/clippy/clippy_lints/src/pub_use.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_ast::ast::{Item, ItemKind, VisibilityKind};
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::declare_lint_pass;
@@ -42,14 +42,10 @@ impl EarlyLintPass for PubUse {
         if let ItemKind::Use(_) = item.kind
             && let VisibilityKind::Public = item.vis.kind
         {
-            span_lint_and_help(
-                cx,
-                PUB_USE,
-                item.span,
-                "using `pub use`",
-                None,
-                "move the exported item to a public module instead",
-            );
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(cx, PUB_USE, item.span, "using `pub use`", |diag| {
+                diag.help("move the exported item to a public module instead");
+            });
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index ef6b4d3aeab..e1e3ded2c79 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -7,7 +7,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
 use clippy_utils::{
-    eq_expr_value, higher, in_constant, is_else_clause, is_lint_allowed, is_path_lang_item, is_res_lang_ctor,
+    eq_expr_value, higher, is_else_clause, is_in_const_context, is_lint_allowed, is_path_lang_item, is_res_lang_ctor,
     pat_and_expr_can_be_question_mark, path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt,
     span_contains_comment,
 };
@@ -346,15 +346,13 @@ impl<'tcx> LateLintPass<'tcx> for QuestionMark {
             return;
         }
 
-        if !self.inside_try_block() && !in_constant(cx, stmt.hir_id) {
+        if !self.inside_try_block() && !is_in_const_context(cx) {
             check_let_some_else_return_none(cx, stmt);
         }
         self.check_manual_let_else(cx, stmt);
     }
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if !self.inside_try_block()
-            && !in_constant(cx, expr.hir_id)
-            && is_lint_allowed(cx, QUESTION_MARK_USED, expr.hir_id)
+        if !self.inside_try_block() && !is_in_const_context(cx) && is_lint_allowed(cx, QUESTION_MARK_USED, expr.hir_id)
         {
             check_is_none_or_err_and_early_return(cx, expr);
             check_if_let_some_or_err_and_early_return(cx, expr);
diff --git a/src/tools/clippy/clippy_lints/src/question_mark_used.rs b/src/tools/clippy/clippy_lints/src/question_mark_used.rs
index f5e6cb804da..0a974bf9d2f 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark_used.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark_used.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 
 use clippy_utils::macros::span_is_local;
 use rustc_hir::{Expr, ExprKind, MatchSource};
@@ -39,13 +39,15 @@ impl<'tcx> LateLintPass<'tcx> for QuestionMarkUsed {
                 return;
             }
 
-            span_lint_and_help(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 QUESTION_MARK_USED,
                 expr.span,
                 "question mark operator was used",
-                None,
-                "consider using a custom macro or match expression",
+                |diag| {
+                    diag.help("consider using a custom macro or match expression");
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs
index 829fb58bc65..81189fe517c 100644
--- a/src/tools/clippy/clippy_lints/src/ranges.rs
+++ b/src/tools/clippy/clippy_lints/src/ranges.rs
@@ -1,10 +1,10 @@
 use clippy_config::msrvs::{self, Msrv};
 use clippy_config::Conf;
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
 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 clippy_utils::{get_parent_expr, higher, is_in_const_context, is_integer_const, path_to_local};
 use rustc_ast::ast::RangeLimits;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, HirId};
@@ -202,7 +202,7 @@ fn check_possible_range_contains(
     expr: &Expr<'_>,
     span: Span,
 ) {
-    if in_constant(cx, expr.hir_id) {
+    if is_in_const_context(cx) {
         return;
     }
 
@@ -319,7 +319,7 @@ fn check_range_bounds<'a, 'tcx>(cx: &'a LateContext<'tcx>, ex: &'a Expr<'_>) ->
             _ => return None,
         };
         if let Some(id) = path_to_local(l) {
-            if let Some(c) = constant(cx, cx.typeck_results(), r) {
+            if let Some(c) = ConstEvalCtxt::new(cx).eval(r) {
                 return Some(RangeBounds {
                     val: c,
                     expr: r,
@@ -331,7 +331,7 @@ fn check_range_bounds<'a, 'tcx>(cx: &'a LateContext<'tcx>, ex: &'a Expr<'_>) ->
                 });
             }
         } else if let Some(id) = path_to_local(r) {
-            if let Some(c) = constant(cx, cx.typeck_results(), l) {
+            if let Some(c) = ConstEvalCtxt::new(cx).eval(l) {
                 return Some(RangeBounds {
                     val: c,
                     expr: l,
@@ -451,8 +451,9 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) {
     }) = higher::Range::hir(expr)
         && let ty = cx.typeck_results().expr_ty(start)
         && let ty::Int(_) | ty::Uint(_) = ty.kind()
-        && let Some(start_idx) = constant(cx, cx.typeck_results(), start)
-        && let Some(end_idx) = constant(cx, cx.typeck_results(), end)
+        && let ecx = ConstEvalCtxt::new(cx)
+        && let Some(start_idx) = ecx.eval(start)
+        && let Some(end_idx) = ecx.eval(end)
         && let Some(ordering) = Constant::partial_cmp(cx.tcx, ty, &start_idx, &end_idx)
         && is_empty_range(limits, ordering)
     {
diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
index 3416a93e3c4..a1231c082e6 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
@@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
             let (fn_def_id, arg, arg_ty, clone_ret) =
                 unwrap_or_continue!(is_call_with_ref_arg(cx, mir, &terminator.kind));
 
-            let from_borrow = match_def_path(cx, fn_def_id, &paths::CLONE_TRAIT_METHOD)
+            let from_borrow = cx.tcx.lang_items().get(LangItem::CloneFn) == Some(fn_def_id)
                 || cx.tcx.is_diagnostic_item(sym::to_owned_method, fn_def_id)
                 || (cx.tcx.is_diagnostic_item(sym::to_string_method, fn_def_id)
                     && is_type_lang_item(cx, arg_ty, LangItem::String));
diff --git a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
index 82f22ad693d..1c10e84d3ca 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
@@ -1,7 +1,7 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::get_parent_expr;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::ty::{is_type_lang_item, peel_mid_ty_refs};
+use clippy_utils::ty::is_type_lang_item;
+use clippy_utils::{get_parent_expr, peel_middle_ty_refs};
 use rustc_ast::util::parser::PREC_PREFIX;
 use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability};
@@ -82,13 +82,12 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
             && let ExprKind::Index(indexed, range, _) = addressee.kind
             && is_type_lang_item(cx, cx.typeck_results().expr_ty_adjusted(range), LangItem::RangeFull)
         {
-            let (expr_ty, expr_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(expr));
-            let (indexed_ty, indexed_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(indexed));
+            let (expr_ty, expr_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(expr));
+            let (indexed_ty, indexed_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(indexed));
             let parent_expr = get_parent_expr(cx, expr);
             let needs_parens_for_prefix = parent_expr.map_or(false, |parent| parent.precedence().order() > PREC_PREFIX);
-            let mut app = Applicability::MachineApplicable;
 
-            let ((lint, msg), help, sugg) = if expr_ty == indexed_ty {
+            if expr_ty == indexed_ty {
                 if expr_ref_count > indexed_ref_count {
                     // Indexing takes self by reference and can't return a reference to that
                     // reference as it's a local variable. The only way this could happen is if
@@ -99,7 +98,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
                 }
                 let deref_count = indexed_ref_count - expr_ref_count;
 
-                let (lint, reborrow_str, help_str) = if mutability == Mutability::Mut {
+                let ((lint, msg), reborrow_str, help_msg) = if mutability == Mutability::Mut {
                     // The slice was used to reborrow the mutable reference.
                     (DEREF_BY_SLICING_LINT, "&mut *", "reborrow the original value instead")
                 } else if matches!(
@@ -113,8 +112,11 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
                         a.kind,
                         Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. }))
                     )
-                }) {
-                    // The slice was used to make a temporary reference.
+                }) || (matches!(
+                    cx.typeck_results().expr_ty(indexed).ref_mutability(),
+                    Some(Mutability::Mut)
+                ) && mutability == Mutability::Not)
+                {
                     (DEREF_BY_SLICING_LINT, "&*", "reborrow the original value instead")
                 } else if deref_count != 0 {
                     (DEREF_BY_SLICING_LINT, "", "dereference the original value instead")
@@ -122,38 +124,36 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
                     (REDUNDANT_SLICING_LINT, "", "use the original value instead")
                 };
 
-                let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0;
-                let sugg = if (deref_count != 0 || !reborrow_str.is_empty()) && needs_parens_for_prefix {
-                    format!("({reborrow_str}{}{snip})", "*".repeat(deref_count))
-                } else {
-                    format!("{reborrow_str}{}{snip}", "*".repeat(deref_count))
-                };
-
-                (lint, help_str, sugg)
+                span_lint_and_then(cx, lint, expr.span, msg, |diag| {
+                    let mut app = Applicability::MachineApplicable;
+                    let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0;
+                    let sugg = if (deref_count != 0 || !reborrow_str.is_empty()) && needs_parens_for_prefix {
+                        format!("({reborrow_str}{}{snip})", "*".repeat(deref_count))
+                    } else {
+                        format!("{reborrow_str}{}{snip}", "*".repeat(deref_count))
+                    };
+                    diag.span_suggestion(expr.span, help_msg, sugg, app);
+                });
             } 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_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;
-                        let sugg = if needs_parens_for_prefix {
-                            format!("(&{}{}*{snip})", mutability.prefix_str(), "*".repeat(indexed_ref_count))
-                        } else {
-                            format!("&{}{}*{snip}", mutability.prefix_str(), "*".repeat(indexed_ref_count))
-                        };
-                        (DEREF_BY_SLICING_LINT, "dereference the original value instead", sugg)
-                    } else {
-                        return;
+                        let (lint, msg) = DEREF_BY_SLICING_LINT;
+                        span_lint_and_then(cx, lint, expr.span, msg, |diag| {
+                            let mut app = Applicability::MachineApplicable;
+                            let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0;
+                            let sugg = if needs_parens_for_prefix {
+                                format!("(&{}{}*{snip})", mutability.prefix_str(), "*".repeat(indexed_ref_count))
+                            } else {
+                                format!("&{}{}*{snip}", mutability.prefix_str(), "*".repeat(indexed_ref_count))
+                            };
+                            diag.span_suggestion(expr.span, "dereference the original value instead", sugg, app);
+                        });
                     }
-                } else {
-                    return;
                 }
-            } else {
-                return;
-            };
-
-            span_lint_and_sugg(cx, lint, expr.span, msg, help, sugg, app);
+            }
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/ref_patterns.rs b/src/tools/clippy/clippy_lints/src/ref_patterns.rs
index 467038523b4..002c6c41d52 100644
--- a/src/tools/clippy/clippy_lints/src/ref_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/ref_patterns.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_ast::ast::{BindingMode, Pat, PatKind};
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::declare_lint_pass;
@@ -33,14 +33,10 @@ impl EarlyLintPass for RefPatterns {
         if let PatKind::Ident(BindingMode::REF, _, _) = pat.kind
             && !pat.span.from_expansion()
         {
-            span_lint_and_help(
-                cx,
-                REF_PATTERNS,
-                pat.span,
-                "usage of ref pattern",
-                None,
-                "consider using `&` for clarity instead",
-            );
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(cx, REF_PATTERNS, pat.span, "usage of ref pattern", |diag| {
+                diag.help("consider using `&` for clarity instead");
+            });
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs
index 8cacb646f51..95014b23043 100644
--- a/src/tools/clippy/clippy_lints/src/regex.rs
+++ b/src/tools/clippy/clippy_lints/src/regex.rs
@@ -1,6 +1,6 @@
 use std::fmt::Display;
 
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::source::snippet_opt;
 use clippy_utils::{def_path_def_ids, path_def_id, paths};
@@ -148,7 +148,7 @@ fn lint_syntax_error(cx: &LateContext<'_>, error: &regex_syntax::Error, unescape
 }
 
 fn const_str<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option<String> {
-    constant(cx, cx.typeck_results(), e).and_then(|c| match c {
+    ConstEvalCtxt::new(cx).eval(e).and_then(|c| match c {
         Constant::Str(s) => Some(s),
         _ => None,
     })
diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
deleted file mode 100644
index 8e999f3e89a..00000000000
--- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs
+++ /dev/null
@@ -1,65 +0,0 @@
-// This file is managed by `cargo dev rename_lint`. Prefer using that when possible.
-
-#[rustfmt::skip]
-pub static RENAMED_LINTS: &[(&str, &str)] = &[
-    ("clippy::almost_complete_letter_range", "clippy::almost_complete_range"),
-    ("clippy::blacklisted_name", "clippy::disallowed_names"),
-    ("clippy::block_in_if_condition_expr", "clippy::blocks_in_conditions"),
-    ("clippy::block_in_if_condition_stmt", "clippy::blocks_in_conditions"),
-    ("clippy::blocks_in_if_conditions", "clippy::blocks_in_conditions"),
-    ("clippy::box_vec", "clippy::box_collection"),
-    ("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes"),
-    ("clippy::cyclomatic_complexity", "clippy::cognitive_complexity"),
-    ("clippy::derive_hash_xor_eq", "clippy::derived_hash_with_manual_eq"),
-    ("clippy::disallowed_method", "clippy::disallowed_methods"),
-    ("clippy::disallowed_type", "clippy::disallowed_types"),
-    ("clippy::eval_order_dependence", "clippy::mixed_read_write_in_expression"),
-    ("clippy::identity_conversion", "clippy::useless_conversion"),
-    ("clippy::if_let_some_result", "clippy::match_result_ok"),
-    ("clippy::incorrect_clone_impl_on_copy_type", "clippy::non_canonical_clone_impl"),
-    ("clippy::incorrect_partial_ord_impl_on_ord_type", "clippy::non_canonical_partial_ord_impl"),
-    ("clippy::integer_arithmetic", "clippy::arithmetic_side_effects"),
-    ("clippy::logic_bug", "clippy::overly_complex_bool_expr"),
-    ("clippy::new_without_default_derive", "clippy::new_without_default"),
-    ("clippy::option_and_then_some", "clippy::bind_instead_of_map"),
-    ("clippy::option_expect_used", "clippy::expect_used"),
-    ("clippy::option_map_unwrap_or", "clippy::map_unwrap_or"),
-    ("clippy::option_map_unwrap_or_else", "clippy::map_unwrap_or"),
-    ("clippy::option_unwrap_used", "clippy::unwrap_used"),
-    ("clippy::overflow_check_conditional", "clippy::panicking_overflow_checks"),
-    ("clippy::ref_in_deref", "clippy::needless_borrow"),
-    ("clippy::result_expect_used", "clippy::expect_used"),
-    ("clippy::result_map_unwrap_or_else", "clippy::map_unwrap_or"),
-    ("clippy::result_unwrap_used", "clippy::unwrap_used"),
-    ("clippy::single_char_push_str", "clippy::single_char_add_str"),
-    ("clippy::stutter", "clippy::module_name_repetitions"),
-    ("clippy::thread_local_initializer_can_be_made_const", "clippy::missing_const_for_thread_local"),
-    ("clippy::to_string_in_display", "clippy::recursive_format_impl"),
-    ("clippy::unwrap_or_else_default", "clippy::unwrap_or_default"),
-    ("clippy::zero_width_space", "clippy::invisible_characters"),
-    ("clippy::cast_ref_to_mut", "invalid_reference_casting"),
-    ("clippy::clone_double_ref", "suspicious_double_ref_op"),
-    ("clippy::cmp_nan", "invalid_nan_comparisons"),
-    ("clippy::drop_bounds", "drop_bounds"),
-    ("clippy::drop_copy", "dropping_copy_types"),
-    ("clippy::drop_ref", "dropping_references"),
-    ("clippy::fn_null_check", "useless_ptr_null_checks"),
-    ("clippy::for_loop_over_option", "for_loops_over_fallibles"),
-    ("clippy::for_loop_over_result", "for_loops_over_fallibles"),
-    ("clippy::for_loops_over_fallibles", "for_loops_over_fallibles"),
-    ("clippy::forget_copy", "forgetting_copy_types"),
-    ("clippy::forget_ref", "forgetting_references"),
-    ("clippy::into_iter_on_array", "array_into_iter"),
-    ("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"),
-    ("clippy::invalid_ref", "invalid_value"),
-    ("clippy::invalid_utf8_in_unchecked", "invalid_from_utf8_unchecked"),
-    ("clippy::let_underscore_drop", "let_underscore_drop"),
-    ("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums"),
-    ("clippy::panic_params", "non_fmt_panics"),
-    ("clippy::positional_named_format_parameters", "named_arguments_used_positionally"),
-    ("clippy::temporary_cstring_as_ptr", "temporary_cstring_as_ptr"),
-    ("clippy::undropped_manually_drops", "undropped_manually_drops"),
-    ("clippy::unknown_clippy_lints", "unknown_lints"),
-    ("clippy::unused_label", "unused_labels"),
-    ("clippy::vtable_address_comparisons", "ambiguous_wide_pointer_comparisons"),
-];
diff --git a/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs b/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs
index 792d8fc88f0..678681ea425 100644
--- a/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs
+++ b/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher::VecArgs;
 use clippy_utils::macros::matching_root_macro_call;
@@ -69,7 +69,7 @@ fn check_vec_macro(cx: &LateContext<'_>, expr: &Expr<'_>) {
         && let Some(VecArgs::Repeat(repeat_expr, len_expr)) = VecArgs::hir(cx, expr)
         && fn_def_id(cx, repeat_expr).is_some_and(|did| match_def_path(cx, did, &paths::VEC_WITH_CAPACITY))
         && !len_expr.span.from_expansion()
-        && let Some(Constant::Int(2..)) = constant(cx, cx.typeck_results(), expr_or_init(cx, len_expr))
+        && let Some(Constant::Int(2..)) = ConstEvalCtxt::new(cx).eval(expr_or_init(cx, len_expr))
     {
         emit_lint(
             cx,
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index 8ced47b48a4..13016cdadb0 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -395,7 +395,7 @@ fn check_final_expr<'tcx>(
             // Returns may be used to turn an expression into a statement in rustc's AST.
             // This allows the addition of attributes, like `#[allow]` (See: clippy#9361)
             // `#[expect(clippy::needless_return)]` needs to be handled separatly to
-            // actually fullfil the expectation (clippy::#12998)
+            // actually fulfill the expectation (clippy::#12998)
             match cx.tcx.hir().attrs(expr.hir_id) {
                 [] => {},
                 [attr] => {
diff --git a/src/tools/clippy/clippy_lints/src/semicolon_block.rs b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
index 7615c21276d..09f1c112352 100644
--- a/src/tools/clippy/clippy_lints/src/semicolon_block.rs
+++ b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
@@ -1,5 +1,5 @@
 use clippy_config::Conf;
-use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_then};
+use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_errors::Applicability;
 use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -92,11 +92,10 @@ impl SemicolonBlock {
             semi_span,
             "consider moving the `;` inside the block for consistent formatting",
             |diag| {
-                multispan_sugg_with_applicability(
-                    diag,
+                diag.multipart_suggestion(
                     "put the `;` here",
+                    vec![(remove_span, String::new()), (insert_span, ";".to_owned())],
                     Applicability::MachineApplicable,
-                    [(remove_span, String::new()), (insert_span, ";".to_owned())],
                 );
             },
         );
@@ -124,11 +123,10 @@ impl SemicolonBlock {
             block.span,
             "consider moving the `;` outside the block for consistent formatting",
             |diag| {
-                multispan_sugg_with_applicability(
-                    diag,
+                diag.multipart_suggestion(
                     "put the `;` here",
+                    vec![(remove_span, String::new()), (insert_span, ";".to_owned())],
                     Applicability::MachineApplicable,
-                    [(remove_span, String::new()), (insert_span, ";".to_owned())],
                 );
             },
         );
diff --git a/src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs b/src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs
index 5e65b9fa517..e6fe7649397 100644
--- a/src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs
+++ b/src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs
@@ -12,8 +12,8 @@ use rustc_span::{sym, Span};
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for usage of `contains` to see if a value is not
-    /// present on `HashSet` followed by a `insert`.
+    /// Checks for usage of `contains` to see if a value is not present
+    /// in a set like `HashSet` or `BTreeSet`, followed by an `insert`.
     ///
     /// ### Why is this bad?
     /// Using just `insert` and checking the returned `bool` is more efficient.
@@ -45,12 +45,12 @@ declare_clippy_lint! {
     #[clippy::version = "1.80.0"]
     pub SET_CONTAINS_OR_INSERT,
     nursery,
-    "call to `HashSet::contains` followed by `HashSet::insert`"
+    "call to `<set>::contains` followed by `<set>::insert`"
 }
 
-declare_lint_pass!(HashsetInsertAfterContains => [SET_CONTAINS_OR_INSERT]);
+declare_lint_pass!(SetContainsOrInsert => [SET_CONTAINS_OR_INSERT]);
 
-impl<'tcx> LateLintPass<'tcx> for HashsetInsertAfterContains {
+impl<'tcx> LateLintPass<'tcx> for SetContainsOrInsert {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if !expr.span.from_expansion()
             && let Some(higher::If {
@@ -58,14 +58,14 @@ impl<'tcx> LateLintPass<'tcx> for HashsetInsertAfterContains {
                 then: then_expr,
                 ..
             }) = higher::If::hir(expr)
-            && let Some(contains_expr) = try_parse_op_call(cx, cond_expr, sym!(contains))//try_parse_contains(cx, cond_expr)
+            && let Some((contains_expr, sym)) = try_parse_op_call(cx, cond_expr, sym!(contains))//try_parse_contains(cx, cond_expr)
             && let Some(insert_expr) = find_insert_calls(cx, &contains_expr, then_expr)
         {
             span_lint(
                 cx,
                 SET_CONTAINS_OR_INSERT,
                 vec![contains_expr.span, insert_expr.span],
-                "usage of `HashSet::insert` after `HashSet::contains`",
+                format!("usage of `{sym}::insert` after `{sym}::contains`"),
             );
         }
     }
@@ -77,7 +77,11 @@ struct OpExpr<'tcx> {
     span: Span,
 }
 
-fn try_parse_op_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, symbol: Symbol) -> Option<OpExpr<'tcx>> {
+fn try_parse_op_call<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    symbol: Symbol,
+) -> Option<(OpExpr<'tcx>, Symbol)> {
     let expr = peel_hir_expr_while(expr, |e| {
         if let ExprKind::Unary(UnOp::Not, e) = e.kind {
             Some(e)
@@ -97,11 +101,12 @@ fn try_parse_op_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, symbol:
         });
         let receiver = receiver.peel_borrows();
         let receiver_ty = cx.typeck_results().expr_ty(receiver).peel_refs();
-        if value.span.eq_ctxt(expr.span)
-            && is_type_diagnostic_item(cx, receiver_ty, sym::HashSet)
-            && path.ident.name == symbol
-        {
-            return Some(OpExpr { receiver, value, span });
+        if value.span.eq_ctxt(expr.span) && path.ident.name == symbol {
+            for sym in &[sym::HashSet, sym::BTreeSet] {
+                if is_type_diagnostic_item(cx, receiver_ty, *sym) {
+                    return Some((OpExpr { receiver, value, span }, *sym));
+                }
+            }
         }
     }
     None
@@ -113,7 +118,7 @@ fn find_insert_calls<'tcx>(
     expr: &'tcx Expr<'_>,
 ) -> Option<OpExpr<'tcx>> {
     for_each_expr(cx, expr, |e| {
-        if let Some(insert_expr) = try_parse_op_call(cx, e, sym!(insert))
+        if let Some((insert_expr, _)) = try_parse_op_call(cx, e, sym!(insert))
             && SpanlessEq::new(cx).eq_expr(contains_expr.receiver, insert_expr.receiver)
             && SpanlessEq::new(cx).eq_expr(contains_expr.value, insert_expr.value)
         {
diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs
index 80f5fd0b494..7ae0310b6d9 100644
--- a/src/tools/clippy/clippy_lints/src/shadow.rs
+++ b/src/tools/clippy/clippy_lints/src/shadow.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_note;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet;
 use clippy_utils::visitors::is_local_used;
 use rustc_data_structures::fx::FxHashMap;
@@ -194,14 +194,9 @@ fn lint_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, shadowed: HirId, span: Span)
             (SHADOW_UNRELATED, msg)
         },
     };
-    span_lint_and_note(
-        cx,
-        lint,
-        span,
-        msg,
-        Some(cx.tcx.hir().span(shadowed)),
-        "previous binding is here",
-    );
+    span_lint_and_then(cx, lint, span, msg, |diag| {
+        diag.span_note(cx.tcx.hir().span(shadowed), "previous binding is here");
+    });
 }
 
 /// Returns true if the expression is a simple transformation of a local binding such as `&x`
diff --git a/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs b/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs
index 72feb977c31..d92b890950a 100644
--- a/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs
+++ b/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_ast::ast::{GenericParam, GenericParamKind};
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
@@ -48,13 +48,15 @@ impl EarlyLintPass for SingleCharLifetimeNames {
 
         if let GenericParamKind::Lifetime = param.kind {
             if !param.is_placeholder && param.ident.as_str().len() <= 2 {
-                span_lint_and_help(
+                #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+                span_lint_and_then(
                     ctx,
                     SINGLE_CHAR_LIFETIME_NAMES,
                     param.ident.span,
                     "single-character lifetime names are likely uninformative",
-                    None,
-                    "use a more informative name",
+                    |diag| {
+                        diag.help("use a more informative name");
+                    },
                 );
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/size_of_ref.rs b/src/tools/clippy/clippy_lints/src/size_of_ref.rs
index 8d7f12af86e..b3d32a6d7d8 100644
--- a/src/tools/clippy/clippy_lints/src/size_of_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/size_of_ref.rs
@@ -1,6 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::path_def_id;
-use clippy_utils::ty::peel_mid_ty_refs;
+use clippy_utils::{path_def_id, peel_middle_ty_refs};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
@@ -60,7 +59,7 @@ impl LateLintPass<'_> for SizeOfRef {
             && let Some(def_id) = path_def_id(cx, path)
             && cx.tcx.is_diagnostic_item(sym::mem_size_of_val, def_id)
             && let arg_ty = cx.typeck_results().expr_ty(arg)
-            && peel_mid_ty_refs(arg_ty).1 > 1
+            && peel_middle_ty_refs(arg_ty).1 > 1
         {
             span_lint_and_help(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
index 12b70075a3d..974e21df817 100644
--- a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
+++ b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
@@ -1,11 +1,15 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_config::msrvs::Msrv;
+use clippy_config::Conf;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_from_proc_macro;
+use rustc_attr::{StabilityLevel, StableSince};
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{HirId, Path, PathSegment};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
+use rustc_semver::RustcVersion;
 use rustc_session::impl_lint_pass;
 use rustc_span::symbol::kw;
 use rustc_span::{sym, Span};
@@ -66,6 +70,10 @@ declare_clippy_lint! {
     /// imported from core to ensure disabling `alloc` does not cause the crate to fail to compile. This lint
     /// is also useful for crates migrating to become `no_std` compatible.
     ///
+    /// ### Known problems
+    /// The lint is only partially aware of the required MSRV for items that were originally in `std` but moved
+    /// to `core`.
+    ///
     /// ### Example
     /// ```no_run
     /// # extern crate alloc;
@@ -81,20 +89,30 @@ declare_clippy_lint! {
     "type is imported from alloc when available in core"
 }
 
-#[derive(Default)]
 pub struct StdReexports {
     // Paths which can be either a module or a macro (e.g. `std::env`) will cause this check to happen
     // twice. First for the mod, second for the macro. This is used to avoid the lint reporting for the macro
     // when the path could be also be used to access the module.
     prev_span: Span,
+    msrv: Msrv,
 }
+
+impl StdReexports {
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            prev_span: Span::default(),
+            msrv: conf.msrv.clone(),
+        }
+    }
+}
+
 impl_lint_pass!(StdReexports => [STD_INSTEAD_OF_CORE, STD_INSTEAD_OF_ALLOC, ALLOC_INSTEAD_OF_CORE]);
 
 impl<'tcx> LateLintPass<'tcx> for StdReexports {
     fn check_path(&mut self, cx: &LateContext<'tcx>, path: &Path<'tcx>, _: HirId) {
         if let Res::Def(_, def_id) = path.res
             && let Some(first_segment) = get_first_segment(path)
-            && is_stable(cx, def_id)
+            && is_stable(cx, def_id, &self.msrv)
             && !in_external_macro(cx.sess(), path.span)
             && !is_from_proc_macro(cx, &first_segment.ident)
         {
@@ -118,19 +136,27 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
                 _ => return,
             };
             if first_segment.ident.span != self.prev_span {
-                span_lint_and_sugg(
+                #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+                span_lint_and_then(
                     cx,
                     lint,
                     first_segment.ident.span,
                     format!("used import from `{used_mod}` instead of `{replace_with}`"),
-                    format!("consider importing the item from `{replace_with}`"),
-                    replace_with.to_string(),
-                    Applicability::MachineApplicable,
+                    |diag| {
+                        diag.span_suggestion(
+                            first_segment.ident.span,
+                            format!("consider importing the item from `{replace_with}`"),
+                            replace_with.to_string(),
+                            Applicability::MachineApplicable,
+                        );
+                    },
                 );
                 self.prev_span = first_segment.ident.span;
             }
         }
     }
+
+    extract_msrv_attr!(LateContext);
 }
 
 /// Returns the first named segment of a [`Path`].
@@ -146,16 +172,29 @@ fn get_first_segment<'tcx>(path: &Path<'tcx>) -> Option<&'tcx PathSegment<'tcx>>
     }
 }
 
-/// Checks if all ancestors of `def_id` are stable, to avoid linting
-/// [unstable moves](https://github.com/rust-lang/rust/pull/95956)
-fn is_stable(cx: &LateContext<'_>, mut def_id: DefId) -> bool {
+/// Checks if all ancestors of `def_id` meet `msrv` to avoid linting [unstable moves](https://github.com/rust-lang/rust/pull/95956)
+/// or now stable moves that were once unstable.
+///
+/// Does not catch individually moved items
+fn is_stable(cx: &LateContext<'_>, mut def_id: DefId, msrv: &Msrv) -> bool {
     loop {
-        if cx
-            .tcx
-            .lookup_stability(def_id)
-            .map_or(false, |stability| stability.is_unstable())
+        if let Some(stability) = cx.tcx.lookup_stability(def_id)
+            && let StabilityLevel::Stable {
+                since,
+                allowed_through_unstable_modules: false,
+            } = stability.level
         {
-            return false;
+            let stable = match since {
+                StableSince::Version(v) => {
+                    msrv.meets(RustcVersion::new(v.major.into(), v.minor.into(), v.patch.into()))
+                },
+                StableSince::Current => msrv.current().is_none(),
+                StableSince::Err => false,
+            };
+
+            if !stable {
+                return false;
+            }
         }
 
         match cx.tcx.opt_parent(def_id) {
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index 7da661485ab..cfc387886dc 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg};
+use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::{snippet, snippet_with_applicability};
 use clippy_utils::ty::is_type_lang_item;
 use clippy_utils::{
@@ -399,17 +399,16 @@ impl<'tcx> LateLintPass<'tcx> for StrToString {
             && let ty::Ref(_, ty, ..) = ty.kind()
             && ty.is_str()
         {
-            let mut applicability = Applicability::MachineApplicable;
-            let snippet = snippet_with_applicability(cx, self_arg.span, "..", &mut applicability);
-
-            span_lint_and_sugg(
+            span_lint_and_then(
                 cx,
                 STR_TO_STRING,
                 expr.span,
                 "`to_string()` called on a `&str`",
-                "try",
-                format!("{snippet}.to_owned()"),
-                applicability,
+                |diag| {
+                    let mut applicability = Applicability::MachineApplicable;
+                    let snippet = snippet_with_applicability(cx, self_arg.span, "..", &mut applicability);
+                    diag.span_suggestion(expr.span, "try", format!("{snippet}.to_owned()"), applicability);
+                },
             );
         }
     }
@@ -455,13 +454,15 @@ impl<'tcx> LateLintPass<'tcx> for StringToString {
             && let ty = cx.typeck_results().expr_ty(self_arg)
             && is_type_lang_item(cx, ty, LangItem::String)
         {
-            span_lint_and_help(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 STRING_TO_STRING,
                 expr.span,
                 "`to_string()` called on a `String`",
-                None,
-                "consider using `.clone()`",
+                |diag| {
+                    diag.help("consider using `.clone()`");
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs b/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs
index d150a5f858a..d1d822a5532 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::numeric_literal::NumericLiteral;
 use clippy_utils::source::snippet;
 use rustc_ast::LitKind;
@@ -43,14 +43,19 @@ impl LateLintPass<'_> for ConfusingXorAndPow {
             && NumericLiteral::from_lit_kind(&snippet(cx, lit_right.span, ".."), &lit_right.node)
                 .is_some_and(|x| x.is_decimal())
         {
-            span_lint_and_sugg(
+            span_lint_and_then(
                 cx,
                 SUSPICIOUS_XOR_USED_AS_POW,
                 expr.span,
                 "`^` is not the exponentiation operator",
-                "did you mean to write",
-                format!("{}.pow({})", lit_left.node, lit_right.node),
-                Applicability::MaybeIncorrect,
+                |diag| {
+                    diag.span_suggestion_verbose(
+                        expr.span,
+                        "did you mean to write",
+                        format!("{}.pow({})", lit_left.node, lit_right.node),
+                        Applicability::MaybeIncorrect,
+                    );
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs
index 93bad865809..197011cde3a 100644
--- a/src/tools/clippy/clippy_lints/src/swap.rs
+++ b/src/tools/clippy/clippy_lints/src/swap.rs
@@ -3,7 +3,7 @@ use clippy_utils::source::{snippet_indent, snippet_with_context};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::is_type_diagnostic_item;
 
-use clippy_utils::{can_mut_borrow_both, eq_expr_value, in_constant, std_or_core};
+use clippy_utils::{can_mut_borrow_both, eq_expr_value, is_in_const_context, std_or_core};
 use itertools::Itertools;
 
 use rustc_hir::intravisit::{walk_expr, Visitor};
@@ -170,7 +170,7 @@ fn generate_swap_warning<'tcx>(
 
 /// Implementation of the `MANUAL_SWAP` lint.
 fn check_manual_swap<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
-    if in_constant(cx, block.hir_id) {
+    if is_in_const_context(cx) {
         return;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs b/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs
index 58e42892c41..25d0a16e2ab 100644
--- a/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs
+++ b/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_note;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::{is_in_cfg_test, is_in_test_function};
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Body, FnDecl};
@@ -61,13 +61,15 @@ impl LateLintPass<'_> for TestsOutsideTestModule {
             && is_in_test_function(cx.tcx, body.id().hir_id)
             && !is_in_cfg_test(cx.tcx, body.id().hir_id)
         {
-            span_lint_and_note(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 TESTS_OUTSIDE_TEST_MODULE,
                 sp,
                 "this function marked with #[test] is outside a #[cfg(test)] module",
-                None,
-                "move it to a testing module marked with #[cfg(test)]",
+                |diag| {
+                    diag.note("move it to a testing module marked with #[cfg(test)]");
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
index 9c6813a54b9..373bf61d8ff 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
@@ -21,7 +21,7 @@ mod wrong_transmute;
 
 use clippy_config::msrvs::Msrv;
 use clippy_config::Conf;
-use clippy_utils::in_constant;
+use clippy_utils::is_in_const_context;
 use rustc_hir::{Expr, ExprKind, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
@@ -595,7 +595,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
             // - from/to bits (https://github.com/rust-lang/rust/issues/73736)
             // - dereferencing raw pointers (https://github.com/rust-lang/rust/issues/51911)
             // - char conversions (https://github.com/rust-lang/rust/issues/89259)
-            let const_context = in_constant(cx, e.hir_id);
+            let const_context = is_in_const_context(cx);
 
             let (from_ty, from_ty_adjusted) = match cx.typeck_results().expr_adjustments(arg) {
                 [] => (cx.typeck_results().expr_ty(arg), false),
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs
index b26365e34ab..7acf3be51fb 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::{is_integer_literal, is_path_diagnostic_item};
 use rustc_hir::{Expr, ExprKind};
@@ -33,10 +33,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t
         // Catching:
         // transmute over constants that resolve to `null`.
         ExprKind::Path(ref _qpath)
-            if matches!(
-                constant(cx, cx.typeck_results(), casts_peeled),
-                Some(Constant::RawPtr(0))
-            ) =>
+            if matches!(ConstEvalCtxt::new(cx).eval(casts_peeled), Some(Constant::RawPtr(0))) =>
         {
             lint_expr(cx, expr);
             true
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs b/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs
index 471bd44b5d5..544014bd32b 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::{is_integer_literal, is_path_diagnostic_item};
 use rustc_hir::{Expr, ExprKind};
@@ -17,7 +17,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t
 
     // Catching transmute over constants that resolve to `null`.
     if let ExprKind::Path(ref _qpath) = arg.kind
-        && let Some(Constant::RawPtr(0)) = constant(cx, cx.typeck_results(), arg)
+        && let Some(Constant::RawPtr(0)) = ConstEvalCtxt::new(cx).eval(arg)
     {
         span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG);
         return true;
diff --git a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
index 83cc9f2d8df..2fcfc71a8c7 100644
--- a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
+++ b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
@@ -48,15 +48,15 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m
                 let inner_snippet = snippet(cx, inner.span, "..");
                 let suggestion = match &inner.kind {
                     TyKind::TraitObject(bounds, lt_bound, _) if bounds.len() > 1 || !lt_bound.is_elided() => {
-                        format!("&{ltopt}({})", &inner_snippet)
+                        format!("&{ltopt}({inner_snippet})")
                     },
                     TyKind::Path(qpath)
                         if get_bounds_if_impl_trait(cx, qpath, inner.hir_id)
                             .map_or(false, |bounds| bounds.len() > 1) =>
                     {
-                        format!("&{ltopt}({})", &inner_snippet)
+                        format!("&{ltopt}({inner_snippet})")
                     },
-                    _ => format!("&{ltopt}{}", &inner_snippet),
+                    _ => format!("&{ltopt}{inner_snippet}"),
                 };
                 span_lint_and_sugg(
                     cx,
@@ -82,16 +82,14 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m
 // Returns true if given type is `Any` trait.
 fn is_any_trait(cx: &LateContext<'_>, t: &hir::Ty<'_>) -> bool {
     if let TyKind::TraitObject(traits, ..) = t.kind {
-        return traits
-            .iter()
-            .any(|(bound, _)| {
-                if let Some(trait_did) = bound.trait_ref.trait_def_id()
-                    && cx.tcx.is_diagnostic_item(sym::Any, trait_did)
-                {
-                    return true;
-                }
-                false
-            });
+        return traits.iter().any(|(bound, _)| {
+            if let Some(trait_did) = bound.trait_ref.trait_def_id()
+                && cx.tcx.is_diagnostic_item(sym::Any, trait_did)
+            {
+                return true;
+            }
+            false
+        });
     }
 
     false
diff --git a/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs b/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs
index f6c2d8d5a5e..d691f1878b1 100644
--- a/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs
+++ b/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::{path_def_id, qpath_generic_tys};
 use rustc_errors::Applicability;
@@ -13,14 +13,15 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
     let app = Applicability::Unspecified;
     if cx.tcx.is_diagnostic_item(sym::Rc, def_id) {
         if let Some(alternate) = match_buffer_type(cx, qpath) {
-            span_lint_and_sugg(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 RC_BUFFER,
                 hir_ty.span,
                 "usage of `Rc<T>` when T is a buffer type",
-                "try",
-                format!("Rc<{alternate}>"),
-                app,
+                |diag| {
+                    diag.span_suggestion(hir_ty.span, "try", format!("Rc<{alternate}>"), app);
+                },
             );
         } else {
             let Some(ty) = qpath_generic_tys(qpath).next() else {
@@ -35,31 +36,37 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
                 Some(ty) => ty.span,
                 None => return false,
             };
-            let mut applicability = app;
-            span_lint_and_sugg(
+            span_lint_and_then(
                 cx,
                 RC_BUFFER,
                 hir_ty.span,
                 "usage of `Rc<T>` when T is a buffer type",
-                "try",
-                format!(
-                    "Rc<[{}]>",
-                    snippet_with_applicability(cx, inner_span, "..", &mut applicability)
-                ),
-                app,
+                |diag| {
+                    let mut applicability = app;
+                    diag.span_suggestion(
+                        hir_ty.span,
+                        "try",
+                        format!(
+                            "Rc<[{}]>",
+                            snippet_with_applicability(cx, inner_span, "..", &mut applicability)
+                        ),
+                        app,
+                    );
+                },
             );
             return true;
         }
     } else if cx.tcx.is_diagnostic_item(sym::Arc, def_id) {
         if let Some(alternate) = match_buffer_type(cx, qpath) {
-            span_lint_and_sugg(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 RC_BUFFER,
                 hir_ty.span,
                 "usage of `Arc<T>` when T is a buffer type",
-                "try",
-                format!("Arc<{alternate}>"),
-                app,
+                |diag| {
+                    diag.span_suggestion(hir_ty.span, "try", format!("Arc<{alternate}>"), app);
+                },
             );
         } else if let Some(ty) = qpath_generic_tys(qpath).next() {
             let Some(id) = path_def_id(cx, ty) else { return false };
@@ -71,18 +78,23 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
                 Some(ty) => ty.span,
                 None => return false,
             };
-            let mut applicability = app;
-            span_lint_and_sugg(
+            span_lint_and_then(
                 cx,
                 RC_BUFFER,
                 hir_ty.span,
                 "usage of `Arc<T>` when T is a buffer type",
-                "try",
-                format!(
-                    "Arc<[{}]>",
-                    snippet_with_applicability(cx, inner_span, "..", &mut applicability)
-                ),
-                app,
+                |diag| {
+                    let mut applicability = app;
+                    diag.span_suggestion(
+                        hir_ty.span,
+                        "try",
+                        format!(
+                            "Arc<[{}]>",
+                            snippet_with_applicability(cx, inner_span, "..", &mut applicability)
+                        ),
+                        app,
+                    );
+                },
             );
             return true;
         }
diff --git a/src/tools/clippy/clippy_lints/src/types/rc_mutex.rs b/src/tools/clippy/clippy_lints/src/types/rc_mutex.rs
index afc31921704..7b13debc01e 100644
--- a/src/tools/clippy/clippy_lints/src/types/rc_mutex.rs
+++ b/src/tools/clippy/clippy_lints/src/types/rc_mutex.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::{path_def_id, qpath_generic_tys};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{self as hir, QPath};
@@ -13,14 +13,10 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
         && let Some(id) = path_def_id(cx, arg)
         && cx.tcx.is_diagnostic_item(sym::Mutex, id)
     {
-        span_lint_and_help(
-            cx,
-            RC_MUTEX,
-            hir_ty.span,
-            "usage of `Rc<Mutex<_>>`",
-            None,
-            "consider using `Rc<RefCell<_>>` or `Arc<Mutex<_>>` instead",
-        );
+        #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+        span_lint_and_then(cx, RC_MUTEX, hir_ty.span, "usage of `Rc<Mutex<_>>`", |diag| {
+            diag.help("consider using `Rc<RefCell<_>>` or `Arc<Mutex<_>>` instead");
+        });
         return true;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
index 3ab30bf5dba..f51c5f74d99 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -1,7 +1,7 @@
 use std::ops::ControlFlow;
 
 use clippy_config::Conf;
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_lint_allowed;
 use clippy_utils::source::walk_span_to_context;
 use clippy_utils::visitors::{for_each_expr, Descend};
@@ -129,13 +129,15 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
                 block.span
             };
 
-            span_lint_and_help(
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
                 cx,
                 UNDOCUMENTED_UNSAFE_BLOCKS,
                 span,
                 "unsafe block missing a safety comment",
-                None,
-                "consider adding a safety comment on the preceding line",
+                |diag| {
+                    diag.help("consider adding a safety comment on the preceding line");
+                },
             );
         }
 
@@ -145,13 +147,14 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
             && let HasSafetyComment::Yes(pos) = stmt_has_safety_comment(cx, tail.span, tail.hir_id)
             && let Some(help_span) = expr_has_unnecessary_safety_comment(cx, tail, pos)
         {
-            span_lint_and_help(
+            span_lint_and_then(
                 cx,
                 UNNECESSARY_SAFETY_COMMENT,
                 tail.span,
                 "expression has unnecessary safety comment",
-                Some(help_span),
-                "consider removing the safety comment",
+                |diag| {
+                    diag.span_help(help_span, "consider removing the safety comment");
+                },
             );
         }
     }
@@ -168,13 +171,14 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
             && let HasSafetyComment::Yes(pos) = stmt_has_safety_comment(cx, stmt.span, stmt.hir_id)
             && let Some(help_span) = expr_has_unnecessary_safety_comment(cx, expr, pos)
         {
-            span_lint_and_help(
+            span_lint_and_then(
                 cx,
                 UNNECESSARY_SAFETY_COMMENT,
                 stmt.span,
                 "statement has unnecessary safety comment",
-                Some(help_span),
-                "consider removing the safety comment",
+                |diag| {
+                    diag.span_help(help_span, "consider removing the safety comment");
+                },
             );
         }
     }
@@ -210,13 +214,15 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
                         item.span
                     };
 
-                    span_lint_and_help(
+                    #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+                    span_lint_and_then(
                         cx,
                         UNDOCUMENTED_UNSAFE_BLOCKS,
                         span,
                         "unsafe impl missing a safety comment",
-                        None,
-                        "consider adding a safety comment on the preceding line",
+                        |diag| {
+                            diag.help("consider adding a safety comment on the preceding line");
+                        },
                     );
                 }
             },
@@ -225,13 +231,14 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
                 if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) {
                     let (span, help_span) = mk_spans(pos);
 
-                    span_lint_and_help(
+                    span_lint_and_then(
                         cx,
                         UNNECESSARY_SAFETY_COMMENT,
                         span,
                         "impl has unnecessary safety comment",
-                        Some(help_span),
-                        "consider removing the safety comment",
+                        |diag| {
+                            diag.span_help(help_span, "consider removing the safety comment");
+                        },
                     );
                 }
             },
@@ -246,13 +253,14 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
                     ) {
                         let (span, help_span) = mk_spans(pos);
 
-                        span_lint_and_help(
+                        span_lint_and_then(
                             cx,
                             UNNECESSARY_SAFETY_COMMENT,
                             span,
                             format!("{} has unnecessary safety comment", item.kind.descr()),
-                            Some(help_span),
-                            "consider removing the safety comment",
+                            |diag| {
+                                diag.span_help(help_span, "consider removing the safety comment");
+                            },
                         );
                     }
                 }
@@ -263,13 +271,14 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
                 if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) {
                     let (span, help_span) = mk_spans(pos);
 
-                    span_lint_and_help(
+                    span_lint_and_then(
                         cx,
                         UNNECESSARY_SAFETY_COMMENT,
                         span,
                         format!("{} has unnecessary safety comment", item.kind.descr()),
-                        Some(help_span),
-                        "consider removing the safety comment",
+                        |diag| {
+                            diag.span_help(help_span, "consider removing the safety comment");
+                        },
                     );
                 }
             },
diff --git a/src/tools/clippy/clippy_lints/src/unicode.rs b/src/tools/clippy/clippy_lints/src/unicode.rs
index d42697b31d1..e1fc644e4ce 100644
--- a/src/tools/clippy/clippy_lints/src/unicode.rs
+++ b/src/tools/clippy/clippy_lints/src/unicode.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_lint_allowed;
 use clippy_utils::macros::span_is_local;
 use clippy_utils::source::snippet;
@@ -105,45 +105,51 @@ fn check_str(cx: &LateContext<'_>, span: Span, id: HirId) {
 
     let string = snippet(cx, span, "");
     if string.chars().any(|c| ['\u{200B}', '\u{ad}', '\u{2060}'].contains(&c)) {
-        span_lint_and_sugg(
-            cx,
-            INVISIBLE_CHARACTERS,
-            span,
-            "invisible character detected",
-            "consider replacing the string with",
-            string
-                .replace('\u{200B}', "\\u{200B}")
-                .replace('\u{ad}', "\\u{AD}")
-                .replace('\u{2060}', "\\u{2060}"),
-            Applicability::MachineApplicable,
-        );
+        #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+        span_lint_and_then(cx, INVISIBLE_CHARACTERS, span, "invisible character detected", |diag| {
+            diag.span_suggestion(
+                span,
+                "consider replacing the string with",
+                string
+                    .replace('\u{200B}', "\\u{200B}")
+                    .replace('\u{ad}', "\\u{AD}")
+                    .replace('\u{2060}', "\\u{2060}"),
+                Applicability::MachineApplicable,
+            );
+        });
     }
 
     if string.chars().any(|c| c as u32 > 0x7F) {
-        span_lint_and_sugg(
+        #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+        span_lint_and_then(
             cx,
             NON_ASCII_LITERAL,
             span,
             "literal non-ASCII character detected",
-            "consider replacing the string with",
-            if is_lint_allowed(cx, UNICODE_NOT_NFC, id) {
-                escape(string.chars())
-            } else {
-                escape(string.nfc())
+            |diag| {
+                diag.span_suggestion(
+                    span,
+                    "consider replacing the string with",
+                    if is_lint_allowed(cx, UNICODE_NOT_NFC, id) {
+                        escape(string.chars())
+                    } else {
+                        escape(string.nfc())
+                    },
+                    Applicability::MachineApplicable,
+                );
             },
-            Applicability::MachineApplicable,
         );
     }
 
     if is_lint_allowed(cx, NON_ASCII_LITERAL, id) && string.chars().zip(string.nfc()).any(|(a, b)| a != b) {
-        span_lint_and_sugg(
-            cx,
-            UNICODE_NOT_NFC,
-            span,
-            "non-NFC Unicode sequence detected",
-            "consider replacing the string with",
-            string.nfc().collect::<String>(),
-            Applicability::MachineApplicable,
-        );
+        #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+        span_lint_and_then(cx, UNICODE_NOT_NFC, span, "non-NFC Unicode sequence detected", |diag| {
+            diag.span_suggestion(
+                span,
+                "consider replacing the string with",
+                string.nfc().collect::<String>(),
+                Applicability::MachineApplicable,
+            );
+        });
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
index e4e7f7d06e7..080efe983c2 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
@@ -145,7 +145,9 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
                 (
                     "this function's return value is unnecessary".to_string(),
                     "remove the return type...".to_string(),
-                    snippet(cx, fn_decl.output.span(), "..").to_string(),
+                    // FIXME: we should instead get the span including the `->` and suggest an
+                    // empty string for this case.
+                    "()".to_string(),
                     "...and then remove returned values",
                 )
             } else {
diff --git a/src/tools/clippy/clippy_lints/src/unused_result_ok.rs b/src/tools/clippy/clippy_lints/src/unused_result_ok.rs
new file mode 100644
index 00000000000..297288db0a5
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/unused_result_ok.rs
@@ -0,0 +1,59 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_context;
+use clippy_utils::ty::is_type_diagnostic_item;
+use rustc_errors::Applicability;
+use rustc_hir::{ExprKind, Stmt, StmtKind};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::declare_lint_pass;
+use rustc_span::sym;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for calls to `Result::ok()` without using the returned `Option`.
+    ///
+    /// ### Why is this bad?
+    /// Using `Result::ok()` may look like the result is checked like `unwrap` or `expect` would do
+    /// but it only silences the warning caused by `#[must_use]` on the `Result`.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// # fn some_function() -> Result<(), ()> { Ok(()) }
+    /// some_function().ok();
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// # fn some_function() -> Result<(), ()> { Ok(()) }
+    /// let _ = some_function();
+    /// ```
+    #[clippy::version = "1.70.0"]
+    pub UNUSED_RESULT_OK,
+    restriction,
+    "Use of `.ok()` to silence `Result`'s `#[must_use]` is misleading. Use `let _ =` instead."
+}
+declare_lint_pass!(UnusedResultOk => [UNUSED_RESULT_OK]);
+
+impl LateLintPass<'_> for UnusedResultOk {
+    fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) {
+        if let StmtKind::Semi(expr) = stmt.kind
+            && let ExprKind::MethodCall(ok_path, recv, [], ..) = expr.kind //check is expr.ok() has type Result<T,E>.ok(, _)
+            && ok_path.ident.as_str() == "ok"
+            && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result)
+            && !in_external_macro(cx.sess(), stmt.span)
+        {
+            let ctxt = expr.span.ctxt();
+            let mut applicability = Applicability::MaybeIncorrect;
+            let snippet = snippet_with_context(cx, recv.span, ctxt, "", &mut applicability).0;
+            let sugg = format!("let _ = {snippet}");
+            span_lint_and_sugg(
+                cx,
+                UNUSED_RESULT_OK,
+                expr.span,
+                "ignoring a result with `.ok()` is misleading",
+                "consider using `let _ =` and removing the call to `.ok()` instead",
+                sugg,
+                applicability,
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
index b017a6bf665..7c2e23995c1 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant_simple, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::match_type;
@@ -93,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
         if let ExprKind::Call(func, [arg]) = &expr.kind
             && let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind()
             && match_def_path(cx, *def_id, &paths::SYMBOL_INTERN)
-            && let Some(Constant::Str(arg)) = constant_simple(cx, cx.typeck_results(), arg)
+            && let Some(Constant::Str(arg)) = ConstEvalCtxt::new(cx).eval_simple(arg)
             && let value = Symbol::intern(&arg).as_u32()
             && let Some(&def_id) = self.symbol_map.get(&value)
         {
@@ -199,7 +199,7 @@ impl InterningDefinedSymbol {
             });
         }
         // is a string constant
-        if let Some(Constant::Str(s)) = constant_simple(cx, cx.typeck_results(), expr) {
+        if let Some(Constant::Str(s)) = ConstEvalCtxt::new(cx).eval_simple(expr) {
             let value = Symbol::intern(&s).as_u32();
             // ...which matches a symbol constant
             if let Some(&def_id) = self.symbol_map.get(&value) {
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 980437259c3..0ffcb433481 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
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant_simple, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::def_path_res;
 use clippy_utils::diagnostics::span_lint;
 use rustc_hir as hir;
@@ -32,9 +32,9 @@ impl<'tcx> LateLintPass<'tcx> for InvalidPaths {
         let mod_name = &cx.tcx.item_name(local_def_id.to_def_id());
         if mod_name.as_str() == "paths"
             && let hir::ItemKind::Const(.., body_id) = item.kind
-            && let body = cx.tcx.hir().body(body_id)
-            && let typeck_results = cx.tcx.typeck_body(body_id)
-            && let Some(Constant::Vec(path)) = constant_simple(cx, typeck_results, body.value)
+            && let Some(Constant::Vec(path)) =
+                ConstEvalCtxt::with_env(cx.tcx, cx.tcx.param_env(item.owner_id), cx.tcx.typeck(item.owner_id))
+                    .eval_simple(cx.tcx.hir().body(body_id).value)
             && let Some(path) = path
                 .iter()
                 .map(|x| {
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
index 84f84781e71..df342e48d63 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
@@ -1,4 +1,3 @@
-use crate::utils::internal_lints::metadata_collector::is_deprecated_lint;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::macros::root_macro_call_first_node;
 use clippy_utils::{is_lint_allowed, match_def_path, paths};
@@ -87,82 +86,32 @@ declare_clippy_lint! {
     "found clippy lint without `clippy::version` attribute"
 }
 
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for cases of an auto-generated deprecated lint without an updated reason,
-    /// i.e. `"default deprecation note"`.
-    ///
-    /// ### Why is this bad?
-    /// Indicates that the documentation is incomplete.
-    ///
-    /// ### Example
-    /// ```rust,ignore
-    /// declare_deprecated_lint! {
-    ///     /// ### What it does
-    ///     /// Nothing. This lint has been deprecated.
-    ///     ///
-    ///     /// ### Deprecation reason
-    ///     /// TODO
-    ///     #[clippy::version = "1.63.0"]
-    ///     pub COOL_LINT,
-    ///     "default deprecation note"
-    /// }
-    /// ```
-    ///
-    /// Use instead:
-    /// ```rust,ignore
-    /// declare_deprecated_lint! {
-    ///     /// ### What it does
-    ///     /// Nothing. This lint has been deprecated.
-    ///     ///
-    ///     /// ### Deprecation reason
-    ///     /// This lint has been replaced by `cooler_lint`
-    ///     #[clippy::version = "1.63.0"]
-    ///     pub COOL_LINT,
-    ///     "this lint has been replaced by `cooler_lint`"
-    /// }
-    /// ```
-    pub DEFAULT_DEPRECATION_REASON,
-    internal,
-    "found 'default deprecation note' in a deprecated lint declaration"
-}
-
 #[derive(Clone, Debug, Default)]
 pub struct LintWithoutLintPass {
     declared_lints: FxHashMap<Symbol, Span>,
     registered_lints: FxHashSet<Symbol>,
 }
 
-impl_lint_pass!(LintWithoutLintPass => [DEFAULT_LINT, LINT_WITHOUT_LINT_PASS, INVALID_CLIPPY_VERSION_ATTRIBUTE, MISSING_CLIPPY_VERSION_ATTRIBUTE, DEFAULT_DEPRECATION_REASON]);
+impl_lint_pass!(LintWithoutLintPass => [DEFAULT_LINT, LINT_WITHOUT_LINT_PASS, INVALID_CLIPPY_VERSION_ATTRIBUTE, MISSING_CLIPPY_VERSION_ATTRIBUTE]);
 
 impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        if is_lint_allowed(cx, DEFAULT_LINT, item.hir_id())
-            || is_lint_allowed(cx, DEFAULT_DEPRECATION_REASON, item.hir_id())
-        {
+        if is_lint_allowed(cx, DEFAULT_LINT, item.hir_id()) {
             return;
         }
 
         if let hir::ItemKind::Static(ty, Mutability::Not, body_id) = item.kind {
-            let is_lint_ref_ty = is_lint_ref_type(cx, ty);
-            if is_deprecated_lint(cx, ty) || is_lint_ref_ty {
+            if is_lint_ref_type(cx, ty) {
                 check_invalid_clippy_version_attribute(cx, item);
 
                 let expr = &cx.tcx.hir().body(body_id).value;
-                let fields;
-                if is_lint_ref_ty {
-                    if let ExprKind::AddrOf(_, _, inner_exp) = expr.kind
-                        && let ExprKind::Struct(_, struct_fields, _) = inner_exp.kind
-                    {
-                        fields = struct_fields;
-                    } else {
-                        return;
-                    }
-                } else if let ExprKind::Struct(_, struct_fields, _) = expr.kind {
-                    fields = struct_fields;
+                let fields = if let ExprKind::AddrOf(_, _, inner_exp) = expr.kind
+                    && let ExprKind::Struct(_, struct_fields, _) = inner_exp.kind
+                {
+                    struct_fields
                 } else {
                     return;
-                }
+                };
 
                 let field = fields
                     .iter()
@@ -175,25 +124,15 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
                 }) = field.expr.kind
                 {
                     let sym_str = sym.as_str();
-                    if is_lint_ref_ty {
-                        if sym_str == "default lint description" {
-                            span_lint(
-                                cx,
-                                DEFAULT_LINT,
-                                item.span,
-                                format!("the lint `{}` has the default lint description", item.ident.name),
-                            );
-                        }
-
-                        self.declared_lints.insert(item.ident.name, item.span);
-                    } else if sym_str == "default deprecation note" {
+                    if sym_str == "default lint description" {
                         span_lint(
                             cx,
-                            DEFAULT_DEPRECATION_REASON,
+                            DEFAULT_LINT,
                             item.span,
-                            format!("the lint `{}` has the default deprecation reason", item.ident.name),
+                            format!("the lint `{}` has the default lint description", item.ident.name),
                         );
                     }
+                    self.declared_lints.insert(item.ident.name, item.span);
                 }
             }
         } else if let Some(macro_call) = root_macro_call_first_node(cx, item) {
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
index 1c149f20456..57f45aa3e48 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
@@ -7,13 +7,12 @@
 //! during any comparison or mapping. (Please take care of this, it's not fun to spend time on such
 //! a simple mistake)
 
-use crate::renamed_lints::RENAMED_LINTS;
 use crate::utils::internal_lints::lint_without_lint_pass::{extract_clippy_version_value, is_lint_ref_type};
 use clippy_config::{get_configuration_metadata, ClippyConfiguration};
 
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::ty::{match_type, walk_ptrs_ty_depth};
-use clippy_utils::{last_path_segment, match_def_path, match_function_call, match_path, paths};
+use clippy_utils::{last_path_segment, match_function_call, match_path, paths};
 use itertools::Itertools;
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxHashMap;
@@ -85,11 +84,6 @@ const SUGGESTION_DIAG_METHODS: [(&str, bool); 9] = [
     ("tool_only_multipart_suggestion", true),
     ("span_suggestions", true),
 ];
-const SUGGESTION_FUNCTIONS: [&[&str]; 2] = [
-    &["clippy_utils", "diagnostics", "multispan_sugg"],
-    &["clippy_utils", "diagnostics", "multispan_sugg_with_applicability"],
-];
-const DEPRECATED_LINT_TYPE: [&str; 3] = ["clippy_lints", "deprecated_lints", "ClippyDeprecatedLint"];
 
 /// The index of the applicability name of `paths::APPLICABILITY_VALUES`
 const APPLICABILITY_NAME_INDEX: usize = 2;
@@ -165,9 +159,9 @@ impl MetadataCollector {
     fn get_lint_configs(&self, lint_name: &str) -> Option<String> {
         self.config
             .iter()
-            .filter(|config| config.lints.iter().any(|lint| lint == lint_name))
+            .filter(|config| config.lints.iter().any(|&lint| lint == lint_name))
             .map(ToString::to_string)
-            .reduce(|acc, x| acc + &x)
+            .reduce(|acc, x| acc + "\n\n" + &x)
             .map(|configurations| {
                 format!(
                     r#"
@@ -216,6 +210,13 @@ impl Drop for MetadataCollector {
 
         let mut applicability_info = std::mem::take(&mut self.applicability_info);
 
+        // Add deprecated lints
+        self.lints.extend(
+            crate::deprecated_lints::DEPRECATED
+                .iter()
+                .zip(crate::deprecated_lints::DEPRECATED_VERSION)
+                .filter_map(|((lint, reason), version)| LintMetadata::new_deprecated(lint, reason, version)),
+        );
         // Mapping the final data
         let mut lints = std::mem::take(&mut self.lints).into_sorted_vec();
         for x in &mut lints {
@@ -261,7 +262,7 @@ Please use that command to update the file and do not edit it by hand.
 #[derive(Debug, Clone, Serialize, PartialEq, Eq, PartialOrd, Ord)]
 struct LintMetadata {
     id: String,
-    id_span: SerializableSpan,
+    id_span: Option<SerializableSpan>,
     group: String,
     level: String,
     docs: String,
@@ -285,7 +286,7 @@ impl LintMetadata {
     ) -> Self {
         Self {
             id,
-            id_span,
+            id_span: Some(id_span),
             group,
             level: level.to_string(),
             version,
@@ -294,6 +295,29 @@ impl LintMetadata {
             former_ids: BTreeSet::new(),
         }
     }
+
+    fn new_deprecated(name: &str, reason: &str, version: &str) -> Option<Self> {
+        // The reason starts with a lowercase letter and end without a period.
+        // This needs to be fixed for the website.
+        let mut reason = reason.to_owned();
+        if let Some(reason) = reason.get_mut(0..1) {
+            reason.make_ascii_uppercase();
+        }
+        name.strip_prefix("clippy::").map(|name| Self {
+            id: name.into(),
+            id_span: None,
+            group: DEPRECATED_LINT_GROUP_STR.into(),
+            level: DEPRECATED_LINT_LEVEL.into(),
+            version: version.into(),
+            docs: format!(
+                "### What it does\n\n\
+                Nothing. This lint has been deprecated\n\n\
+                ### Deprecation reason\n\n{reason}.\n",
+            ),
+            applicability: None,
+            former_ids: BTreeSet::new(),
+        })
+    }
 }
 
 fn replace_produces(lint_name: &str, docs: &mut String, clippy_project_root: &Path) {
@@ -564,24 +588,6 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector {
                     raw_docs,
                 ));
             }
-
-            if is_deprecated_lint(cx, ty)
-                // disallow check
-                && let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase()
-                // Metadata the little we can get from a deprecated lint
-                && let Some(raw_docs) = extract_attr_docs_or_lint(cx, item)
-            {
-                let version = get_lint_version(cx, item);
-
-                self.lints.push(LintMetadata::new(
-                    lint_name,
-                    SerializableSpan::from_item(cx, item),
-                    DEPRECATED_LINT_GROUP_STR.to_string(),
-                    DEPRECATED_LINT_LEVEL,
-                    version,
-                    raw_docs,
-                ));
-            }
         }
     }
 
@@ -684,6 +690,11 @@ fn cleanup_docs(docs_collection: &Vec<String>) -> String {
                     .find(|&s| !matches!(s, "" | "ignore" | "no_run" | "should_panic"))
                     // if no language is present, fill in "rust"
                     .unwrap_or("rust");
+                let len_diff = line.len() - line.trim_start().len();
+                if len_diff != 0 {
+                    // We put back the indentation.
+                    docs.push_str(&line[..len_diff]);
+                }
                 docs.push_str("```");
                 docs.push_str(lang);
 
@@ -766,16 +777,6 @@ fn get_lint_level_from_group(lint_group: &str) -> Option<&'static str> {
         .find_map(|(group_name, group_level)| (*group_name == lint_group).then_some(*group_level))
 }
 
-pub(super) fn is_deprecated_lint(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
-    if let hir::TyKind::Path(ref path) = ty.kind {
-        if let hir::def::Res::Def(DefKind::Struct, def_id) = cx.qpath_res(path, ty.hir_id) {
-            return match_def_path(cx, def_id, &DEPRECATED_LINT_TYPE);
-        }
-    }
-
-    false
-}
-
 fn collect_renames(lints: &mut Vec<LintMetadata>) {
     for lint in lints {
         let mut collected = String::new();
@@ -783,7 +784,7 @@ fn collect_renames(lints: &mut Vec<LintMetadata>) {
 
         loop {
             if let Some(lint_name) = names.pop() {
-                for (k, v) in RENAMED_LINTS {
+                for (k, v) in crate::deprecated_lints::RENAMED {
                     if let Some(name) = v.strip_prefix(CLIPPY_LINT_GROUP_PREFIX)
                         && name == lint_name
                         && let Some(past_name) = k.strip_prefix(CLIPPY_LINT_GROUP_PREFIX)
@@ -1055,33 +1056,21 @@ impl<'a, 'hir> Visitor<'hir> for IsMultiSpanScanner<'a, 'hir> {
             return;
         }
 
-        match &expr.kind {
-            ExprKind::Call(fn_expr, _args) => {
-                let found_function = SUGGESTION_FUNCTIONS
-                    .iter()
-                    .any(|func_path| match_function_call(self.cx, fn_expr, func_path).is_some());
-                if found_function {
-                    // These functions are all multi part suggestions
-                    self.add_single_span_suggestion();
-                }
-            },
-            ExprKind::MethodCall(path, recv, _, _arg_span) => {
-                let (self_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(recv));
-                if match_type(self.cx, self_ty, &paths::DIAG) {
-                    let called_method = path.ident.name.as_str().to_string();
-                    for (method_name, is_multi_part) in &SUGGESTION_DIAG_METHODS {
-                        if *method_name == called_method {
-                            if *is_multi_part {
-                                self.add_multi_part_suggestion();
-                            } else {
-                                self.add_single_span_suggestion();
-                            }
-                            break;
+        if let ExprKind::MethodCall(path, recv, _, _arg_span) = &expr.kind {
+            let (self_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(recv));
+            if match_type(self.cx, self_ty, &paths::DIAG) {
+                let called_method = path.ident.name.as_str().to_string();
+                for (method_name, is_multi_part) in &SUGGESTION_DIAG_METHODS {
+                    if *method_name == called_method {
+                        if *is_multi_part {
+                            self.add_multi_part_suggestion();
+                        } else {
+                            self.add_single_span_suggestion();
                         }
+                        break;
                     }
                 }
-            },
-            _ => {},
+            }
         }
 
         intravisit::walk_expr(self, expr);
diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs
index a831234906b..228db14d1b7 100644
--- a/src/tools/clippy/clippy_lints/src/vec.rs
+++ b/src/tools/clippy/clippy_lints/src/vec.rs
@@ -3,7 +3,7 @@ use std::ops::ControlFlow;
 
 use clippy_config::msrvs::{self, Msrv};
 use clippy_config::Conf;
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::is_copy;
@@ -159,7 +159,7 @@ impl UselessVec {
 
         let snippet = match *vec_args {
             higher::VecArgs::Repeat(elem, len) => {
-                if let Some(Constant::Int(len_constant)) = constant(cx, cx.typeck_results(), len) {
+                if let Some(Constant::Int(len_constant)) = ConstEvalCtxt::new(cx).eval(len) {
                     // vec![ty; N] works when ty is Clone, [ty; N] requires it to be Copy also
                     if !is_copy(cx, cx.typeck_results().expr_ty(elem)) {
                         return;
diff --git a/src/tools/clippy/clippy_lints/src/visibility.rs b/src/tools/clippy/clippy_lints/src/visibility.rs
index 11dcceca7ab..63f3a5d7f83 100644
--- a/src/tools/clippy/clippy_lints/src/visibility.rs
+++ b/src/tools/clippy/clippy_lints/src/visibility.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_opt;
 use rustc_ast::ast::{Item, VisibilityKind};
 use rustc_errors::Applicability;
@@ -85,14 +85,19 @@ impl EarlyLintPass for Visibility {
             if **path == kw::SelfLower
                 && let Some(false) = is_from_proc_macro(cx, item.vis.span)
             {
-                span_lint_and_sugg(
+                span_lint_and_then(
                     cx,
                     NEEDLESS_PUB_SELF,
                     item.vis.span,
                     format!("unnecessary `pub({}self)`", if *shorthand { "" } else { "in " }),
-                    "remove it",
-                    String::new(),
-                    Applicability::MachineApplicable,
+                    |diag| {
+                        diag.span_suggestion_hidden(
+                            item.vis.span,
+                            "remove it",
+                            String::new(),
+                            Applicability::MachineApplicable,
+                        );
+                    },
                 );
             }
 
@@ -101,14 +106,20 @@ impl EarlyLintPass for Visibility {
                 && let [.., last] = &*path.segments
                 && let Some(false) = is_from_proc_macro(cx, item.vis.span)
             {
-                span_lint_and_sugg(
+                #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+                span_lint_and_then(
                     cx,
                     PUB_WITHOUT_SHORTHAND,
                     item.vis.span,
                     "usage of `pub` with `in`",
-                    "remove it",
-                    format!("pub({})", last.ident),
-                    Applicability::MachineApplicable,
+                    |diag| {
+                        diag.span_suggestion(
+                            item.vis.span,
+                            "remove it",
+                            format!("pub({})", last.ident),
+                            Applicability::MachineApplicable,
+                        );
+                    },
                 );
             }
 
@@ -116,14 +127,20 @@ impl EarlyLintPass for Visibility {
                 && let [.., last] = &*path.segments
                 && let Some(false) = is_from_proc_macro(cx, item.vis.span)
             {
-                span_lint_and_sugg(
+                #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+                span_lint_and_then(
                     cx,
                     PUB_WITH_SHORTHAND,
                     item.vis.span,
                     "usage of `pub` without `in`",
-                    "add it",
-                    format!("pub(in {})", last.ident),
-                    Applicability::MachineApplicable,
+                    |diag| {
+                        diag.span_suggestion(
+                            item.vis.span,
+                            "add it",
+                            format!("pub(in {})", last.ident),
+                            Applicability::MachineApplicable,
+                        );
+                    },
                 );
             }
         }
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 60d8a13d359..5eb207a0aed 100644
--- a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant_simple, Constant};
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_help;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -36,8 +36,9 @@ impl<'tcx> LateLintPass<'tcx> for ZeroDiv {
             // TODO - constant_simple does not fold many operations involving floats.
             // That's probably fine for this lint - it's pretty unlikely that someone would
             // 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)
+            && let ecx = ConstEvalCtxt::new(cx)
+            && let Some(lhs_value) = ecx.eval_simple(left)
+            && let Some(rhs_value) = ecx.eval_simple(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 f0c64fdd573..9fefd94d339 100644
--- a/src/tools/clippy/clippy_utils/Cargo.toml
+++ b/src/tools/clippy/clippy_utils/Cargo.toml
@@ -12,9 +12,6 @@ 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"]
-
 [package.metadata.rust-analyzer]
 # This crate uses #[feature(rustc_private)]
 rustc_private = true
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index de6ccfe476f..e907e4058e5 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -14,12 +14,13 @@ use rustc_lexer::tokenize;
 use rustc_lint::LateContext;
 use rustc_middle::mir::interpret::{alloc_range, Scalar};
 use rustc_middle::mir::ConstValue;
-use rustc_middle::ty::{self, EarlyBinder, FloatTy, GenericArgsRef, IntTy, List, ScalarInt, Ty, TyCtxt, UintTy};
+use rustc_middle::ty::{self, FloatTy, IntTy, ParamEnv, ScalarInt, Ty, TyCtxt, TypeckResults, UintTy};
 use rustc_middle::{bug, mir, span_bug};
 use rustc_span::def_id::DefId;
-use rustc_span::symbol::{Ident, Symbol};
+use rustc_span::symbol::Ident;
 use rustc_span::{sym, SyntaxContext};
 use rustc_target::abi::Size;
+use std::cell::Cell;
 use std::cmp::Ordering;
 use std::hash::{Hash, Hasher};
 use std::iter;
@@ -263,10 +264,10 @@ impl<'tcx> Constant<'tcx> {
     }
 
     /// Returns the integer value or `None` if `self` or `val_type` is not integer type.
-    pub fn int_value(&self, cx: &LateContext<'_>, val_type: Ty<'_>) -> Option<FullInt> {
+    pub fn int_value(&self, tcx: TyCtxt<'_>, val_type: Ty<'_>) -> Option<FullInt> {
         if let Constant::Int(const_int) = *self {
             match *val_type.kind() {
-                ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))),
+                ty::Int(ity) => Some(FullInt::S(sext(tcx, const_int, ity))),
                 ty::Uint(_) => Some(FullInt::U(const_int)),
                 _ => None,
             }
@@ -322,6 +323,7 @@ pub fn lit_to_mir_constant<'tcx>(lit: &LitKind, ty: Option<Ty<'tcx>>) -> Constan
 }
 
 /// The source of a constant value.
+#[derive(Clone, Copy)]
 pub enum ConstantSource {
     /// The value is determined solely from the expression.
     Local,
@@ -331,54 +333,11 @@ pub enum ConstantSource {
     CoreConstant,
 }
 impl ConstantSource {
-    pub fn is_local(&self) -> bool {
+    pub fn is_local(self) -> bool {
         matches!(self, Self::Local)
     }
 }
 
-/// Attempts to check whether the expression is a constant representing an empty slice, str, array,
-/// etc…
-pub fn constant_is_empty(lcx: &LateContext<'_>, e: &Expr<'_>) -> Option<bool> {
-    ConstEvalLateContext::new(lcx, lcx.typeck_results()).expr_is_empty(e)
-}
-
-/// Attempts to evaluate the expression as a constant.
-pub fn constant<'tcx>(
-    lcx: &LateContext<'tcx>,
-    typeck_results: &ty::TypeckResults<'tcx>,
-    e: &Expr<'_>,
-) -> Option<Constant<'tcx>> {
-    ConstEvalLateContext::new(lcx, typeck_results).expr(e)
-}
-
-/// Attempts to evaluate the expression as a constant.
-pub fn constant_with_source<'tcx>(
-    lcx: &LateContext<'tcx>,
-    typeck_results: &ty::TypeckResults<'tcx>,
-    e: &Expr<'_>,
-) -> Option<(Constant<'tcx>, ConstantSource)> {
-    let mut ctxt = ConstEvalLateContext::new(lcx, typeck_results);
-    let res = ctxt.expr(e);
-    res.map(|x| (x, ctxt.source))
-}
-
-/// Attempts to evaluate an expression only if its value is not dependent on other items.
-pub fn constant_simple<'tcx>(
-    lcx: &LateContext<'tcx>,
-    typeck_results: &ty::TypeckResults<'tcx>,
-    e: &Expr<'_>,
-) -> Option<Constant<'tcx>> {
-    constant_with_source(lcx, typeck_results, e).and_then(|(c, s)| s.is_local().then_some(c))
-}
-
-pub fn constant_full_int<'tcx>(
-    lcx: &LateContext<'tcx>,
-    typeck_results: &ty::TypeckResults<'tcx>,
-    e: &Expr<'_>,
-) -> Option<FullInt> {
-    constant_simple(lcx, typeck_results, e)?.int_value(lcx, typeck_results.expr_ty(e))
-}
-
 #[derive(Copy, Clone, Debug, Eq)]
 pub enum FullInt {
     S(i128),
@@ -417,44 +376,87 @@ impl Ord for FullInt {
     }
 }
 
-pub struct ConstEvalLateContext<'a, 'tcx> {
-    lcx: &'a LateContext<'tcx>,
-    typeck_results: &'a ty::TypeckResults<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    source: ConstantSource,
-    args: GenericArgsRef<'tcx>,
+/// The context required to evaluate a constant expression.
+///
+/// This is currently limited to constant folding and reading the value of named constants.
+pub struct ConstEvalCtxt<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    param_env: ParamEnv<'tcx>,
+    typeck: &'tcx TypeckResults<'tcx>,
+    source: Cell<ConstantSource>,
 }
 
-impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
-    pub fn new(lcx: &'a LateContext<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>) -> Self {
+impl<'tcx> ConstEvalCtxt<'tcx> {
+    /// Creates the evaluation context from the lint context. This requires the lint context to be
+    /// in a body (i.e. `cx.enclosing_body.is_some()`).
+    pub fn new(cx: &LateContext<'tcx>) -> Self {
+        Self {
+            tcx: cx.tcx,
+            param_env: cx.param_env,
+            typeck: cx.typeck_results(),
+            source: Cell::new(ConstantSource::Local),
+        }
+    }
+
+    /// Creates an evaluation context.
+    pub fn with_env(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, typeck: &'tcx TypeckResults<'tcx>) -> Self {
         Self {
-            lcx,
-            typeck_results,
-            param_env: lcx.param_env,
-            source: ConstantSource::Local,
-            args: List::empty(),
+            tcx,
+            param_env,
+            typeck,
+            source: Cell::new(ConstantSource::Local),
+        }
+    }
+
+    /// Attempts to evaluate the expression and returns both the value and whether it's dependant on
+    /// other items.
+    pub fn eval_with_source(&self, e: &Expr<'_>) -> Option<(Constant<'tcx>, ConstantSource)> {
+        self.source.set(ConstantSource::Local);
+        self.expr(e).map(|c| (c, self.source.get()))
+    }
+
+    /// Attempts to evaluate the expression.
+    pub fn eval(&self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
+        self.expr(e)
+    }
+
+    /// Attempts to evaluate the expression without accessing other items.
+    pub fn eval_simple(&self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
+        match self.eval_with_source(e) {
+            Some((x, ConstantSource::Local)) => Some(x),
+            _ => None,
+        }
+    }
+
+    /// Attempts to evaluate the expression as an integer without accessing other items.
+    pub fn eval_full_int(&self, e: &Expr<'_>) -> Option<FullInt> {
+        match self.eval_with_source(e) {
+            Some((x, ConstantSource::Local)) => x.int_value(self.tcx, self.typeck.expr_ty(e)),
+            _ => None,
         }
     }
 
     /// Simple constant folding: Insert an expression, get a constant or none.
-    pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
+    fn expr(&self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
         match e.kind {
-            ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.lcx.tcx.hir().body(body).value),
+            ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.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
+                let is_core_crate = if let Some(def_id) = self.typeck.qpath_res(qpath, e.hir_id()).opt_def_id() {
+                    self.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)?;
+                self.fetch_path_and_apply(qpath, e.hir_id, self.typeck.expr_ty(e), |self_, result| {
+                    let result = mir_to_const(self_.tcx, result)?;
                     // 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
-                    };
+                    self_.source.set(
+                        if is_core_crate && !matches!(self_.source.get(), ConstantSource::Constant) {
+                            ConstantSource::CoreConstant
+                        } else {
+                            ConstantSource::Constant
+                        },
+                    );
                     Some(result)
                 })
             },
@@ -463,21 +465,21 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
                 if is_direct_expn_of(e.span, "cfg").is_some() {
                     None
                 } else {
-                    Some(lit_to_mir_constant(&lit.node, self.typeck_results.expr_ty_opt(e)))
+                    Some(lit_to_mir_constant(&lit.node, self.typeck.expr_ty_opt(e)))
                 }
             },
             ExprKind::Array(vec) => self.multi(vec).map(Constant::Vec),
             ExprKind::Tup(tup) => self.multi(tup).map(Constant::Tuple),
             ExprKind::Repeat(value, _) => {
-                let n = match self.typeck_results.expr_ty(e).kind() {
-                    ty::Array(_, n) => n.try_eval_target_usize(self.lcx.tcx, self.lcx.param_env)?,
+                let n = match self.typeck.expr_ty(e).kind() {
+                    ty::Array(_, n) => n.try_eval_target_usize(self.tcx, self.param_env)?,
                     _ => span_bug!(e.span, "typeck error"),
                 };
                 self.expr(value).map(|v| Constant::Repeat(Box::new(v), n))
             },
             ExprKind::Unary(op, operand) => self.expr(operand).and_then(|o| match op {
-                UnOp::Not => self.constant_not(&o, self.typeck_results.expr_ty(e)),
-                UnOp::Neg => self.constant_negate(&o, self.typeck_results.expr_ty(e)),
+                UnOp::Not => self.constant_not(&o, self.typeck.expr_ty(e)),
+                UnOp::Neg => self.constant_negate(&o, self.typeck.expr_ty(e)),
                 UnOp::Deref => Some(if let Constant::Ref(r) = o { *r } else { o }),
             }),
             ExprKind::If(cond, then, ref otherwise) => self.ifthenelse(cond, then, *otherwise),
@@ -486,21 +488,16 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
                 // We only handle a few const functions for now.
                 if args.is_empty()
                     && let ExprKind::Path(qpath) = &callee.kind
-                    && let res = self.typeck_results.qpath_res(qpath, callee.hir_id)
-                    && let Some(def_id) = res.opt_def_id()
-                    && let def_path = self.lcx.get_def_path(def_id)
-                    && let def_path = def_path.iter().take(4).map(Symbol::as_str).collect::<Vec<_>>()
-                    && let ["core", "num", int_impl, "max_value"] = *def_path
+                    && let Some(did) = self.typeck.qpath_res(qpath, callee.hir_id).opt_def_id()
                 {
-                    let value = match int_impl {
-                        "<impl i8>" => i8::MAX as u128,
-                        "<impl i16>" => i16::MAX as u128,
-                        "<impl i32>" => i32::MAX as u128,
-                        "<impl i64>" => i64::MAX as u128,
-                        "<impl i128>" => i128::MAX as u128,
-                        _ => return None,
-                    };
-                    Some(Constant::Int(value))
+                    match self.tcx.get_diagnostic_name(did) {
+                        Some(sym::i8_legacy_fn_max_value) => Some(Constant::Int(i8::MAX as u128)),
+                        Some(sym::i16_legacy_fn_max_value) => Some(Constant::Int(i16::MAX as u128)),
+                        Some(sym::i32_legacy_fn_max_value) => Some(Constant::Int(i32::MAX as u128)),
+                        Some(sym::i64_legacy_fn_max_value) => Some(Constant::Int(i64::MAX as u128)),
+                        Some(sym::i128_legacy_fn_max_value) => Some(Constant::Int(i128::MAX as u128)),
+                        _ => None,
+                    }
                 } else {
                     None
                 }
@@ -512,9 +509,9 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
                 if let Some(Constant::Adt(constant)) = &self.expr(local_expr)
                     && let ty::Adt(adt_def, _) = constant.ty().kind()
                     && adt_def.is_struct()
-                    && let Some(desired_field) = field_of_struct(*adt_def, self.lcx, *constant, field)
+                    && let Some(desired_field) = field_of_struct(*adt_def, self.tcx, *constant, field)
                 {
-                    mir_to_const(self.lcx, desired_field)
+                    mir_to_const(self.tcx, desired_field)
                 } else {
                     result
                 }
@@ -526,21 +523,21 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
     /// Simple constant folding to determine if an expression is an empty slice, str, array, …
     /// `None` will be returned if the constness cannot be determined, or if the resolution
     /// leaves the local crate.
-    pub fn expr_is_empty(&mut self, e: &Expr<'_>) -> Option<bool> {
+    pub fn eval_is_empty(&self, e: &Expr<'_>) -> Option<bool> {
         match e.kind {
-            ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr_is_empty(self.lcx.tcx.hir().body(body).value),
-            ExprKind::DropTemps(e) => self.expr_is_empty(e),
+            ExprKind::ConstBlock(ConstBlock { body, .. }) => self.eval_is_empty(self.tcx.hir().body(body).value),
+            ExprKind::DropTemps(e) => self.eval_is_empty(e),
             ExprKind::Path(ref qpath) => {
                 if !self
-                    .typeck_results
+                    .typeck
                     .qpath_res(qpath, e.hir_id)
                     .opt_def_id()
                     .is_some_and(DefId::is_local)
                 {
                     return None;
                 }
-                self.fetch_path_and_apply(qpath, e.hir_id, self.typeck_results.expr_ty(e), |this, result| {
-                    mir_is_empty(this.lcx, result)
+                self.fetch_path_and_apply(qpath, e.hir_id, self.typeck.expr_ty(e), |self_, result| {
+                    mir_is_empty(self_.tcx, result)
                 })
             },
             ExprKind::Lit(lit) => {
@@ -556,8 +553,8 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
             },
             ExprKind::Array(vec) => self.multi(vec).map(|v| v.is_empty()),
             ExprKind::Repeat(..) => {
-                if let ty::Array(_, n) = self.typeck_results.expr_ty(e).kind() {
-                    Some(n.try_eval_target_usize(self.lcx.tcx, self.lcx.param_env)? == 0)
+                if let ty::Array(_, n) = self.typeck.expr_ty(e).kind() {
+                    Some(n.try_eval_target_usize(self.tcx, self.param_env)? == 0)
                 } else {
                     span_bug!(e.span, "typeck error");
                 }
@@ -574,8 +571,8 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
             Int(value) => {
                 let value = !value;
                 match *ty.kind() {
-                    ty::Int(ity) => Some(Int(unsext(self.lcx.tcx, value as i128, ity))),
-                    ty::Uint(ity) => Some(Int(clip(self.lcx.tcx, value, ity))),
+                    ty::Int(ity) => Some(Int(unsext(self.tcx, value as i128, ity))),
+                    ty::Uint(ity) => Some(Int(clip(self.tcx, value, ity))),
                     _ => None,
                 }
             },
@@ -590,7 +587,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
                 let ty::Int(ity) = *ty.kind() else { return None };
                 let (min, _) = ity.min_max()?;
                 // sign extend
-                let value = sext(self.lcx.tcx, value, ity);
+                let value = sext(self.tcx, value, ity);
 
                 // Applying unary - to the most negative value of any signed integer type panics.
                 if value == min {
@@ -599,7 +596,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
 
                 let value = value.checked_neg()?;
                 // clear unused bits
-                Some(Int(unsext(self.lcx.tcx, value, ity)))
+                Some(Int(unsext(self.tcx, value, ity)))
             },
             F32(f) => Some(F32(-f)),
             F64(f) => Some(F64(-f)),
@@ -609,21 +606,21 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
 
     /// Create `Some(Vec![..])` of all constants, unless there is any
     /// non-constant part.
-    fn multi(&mut self, vec: &[Expr<'_>]) -> Option<Vec<Constant<'tcx>>> {
+    fn multi(&self, vec: &[Expr<'_>]) -> Option<Vec<Constant<'tcx>>> {
         vec.iter().map(|elem| self.expr(elem)).collect::<Option<_>>()
     }
 
     /// Lookup a possibly constant expression from an `ExprKind::Path` and apply a function on it.
-    fn fetch_path_and_apply<T, F>(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>, f: F) -> Option<T>
+    fn fetch_path_and_apply<T, F>(&self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>, f: F) -> Option<T>
     where
-        F: FnOnce(&mut Self, mir::Const<'tcx>) -> Option<T>,
+        F: FnOnce(&Self, mir::Const<'tcx>) -> Option<T>,
     {
-        let res = self.typeck_results.qpath_res(qpath, id);
+        let res = self.typeck.qpath_res(qpath, id);
         match res {
             Res::Def(DefKind::Const | DefKind::AssocConst, def_id) => {
                 // Check if this constant is based on `cfg!(..)`,
                 // which is NOT constant for our purposes.
-                if let Some(node) = self.lcx.tcx.hir().get_if_local(def_id)
+                if let Some(node) = self.tcx.hir().get_if_local(def_id)
                     && let Node::Item(Item {
                         kind: ItemKind::Const(.., body_id),
                         ..
@@ -632,20 +629,14 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
                         kind: ExprKind::Lit(_),
                         span,
                         ..
-                    }) = self.lcx.tcx.hir_node(body_id.hir_id)
+                    }) = self.tcx.hir_node(body_id.hir_id)
                     && is_direct_expn_of(*span, "cfg").is_some()
                 {
                     return None;
                 }
 
-                let args = self.typeck_results.node_args(id);
-                let args = if self.args.is_empty() {
-                    args
-                } else {
-                    EarlyBinder::bind(args).instantiate(self.lcx.tcx, self.args)
-                };
+                let args = self.typeck.node_args(id);
                 let result = self
-                    .lcx
                     .tcx
                     .const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, args), qpath.span())
                     .ok()
@@ -656,7 +647,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
         }
     }
 
-    fn index(&mut self, lhs: &'_ Expr<'_>, index: &'_ Expr<'_>) -> Option<Constant<'tcx>> {
+    fn index(&self, lhs: &'_ Expr<'_>, index: &'_ Expr<'_>) -> Option<Constant<'tcx>> {
         let lhs = self.expr(lhs);
         let index = self.expr(index);
 
@@ -685,8 +676,8 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
         }
     }
 
-    /// A block can only yield a constant if it only has one constant expression.
-    fn block(&mut self, block: &Block<'_>) -> Option<Constant<'tcx>> {
+    /// A block can only yield a constant if it has exactly one constant expression.
+    fn block(&self, block: &Block<'_>) -> Option<Constant<'tcx>> {
         if block.stmts.is_empty()
             && let Some(expr) = block.expr
         {
@@ -696,7 +687,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) = (span.lo..expr_lo).get_source_text(self.lcx)
+                    && let Some(src) = (span.lo..expr_lo).get_source_text(&self.tcx)
                     && let Some(src) = src.as_str()
                 {
                     use rustc_lexer::TokenKind::{BlockComment, LineComment, OpenBrace, Semi, Whitespace};
@@ -705,11 +696,11 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
                         .filter(|t| !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. } | Semi))
                         .eq([OpenBrace])
                     {
-                        self.source = ConstantSource::Constant;
+                        self.source.set(ConstantSource::Constant);
                     }
                 } else {
                     // Unable to access the source. Assume a non-local dependency.
-                    self.source = ConstantSource::Constant;
+                    self.source.set(ConstantSource::Constant);
                 }
             }
 
@@ -719,7 +710,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
         }
     }
 
-    fn ifthenelse(&mut self, cond: &Expr<'_>, then: &Expr<'_>, otherwise: Option<&Expr<'_>>) -> Option<Constant<'tcx>> {
+    fn ifthenelse(&self, cond: &Expr<'_>, then: &Expr<'_>, otherwise: Option<&Expr<'_>>) -> Option<Constant<'tcx>> {
         if let Some(Constant::Bool(b)) = self.expr(cond) {
             if b {
                 self.expr(then)
@@ -731,16 +722,16 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
         }
     }
 
-    fn binop(&mut self, op: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> Option<Constant<'tcx>> {
+    fn binop(&self, op: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> Option<Constant<'tcx>> {
         let l = self.expr(left)?;
         let r = self.expr(right);
         match (l, r) {
-            (Constant::Int(l), Some(Constant::Int(r))) => match *self.typeck_results.expr_ty_opt(left)?.kind() {
+            (Constant::Int(l), Some(Constant::Int(r))) => match *self.typeck.expr_ty_opt(left)?.kind() {
                 ty::Int(ity) => {
                     let (ty_min_value, _) = ity.min_max()?;
                     let bits = ity.bits();
-                    let l = sext(self.lcx.tcx, l, ity);
-                    let r = sext(self.lcx.tcx, r, ity);
+                    let l = sext(self.tcx, l, ity);
+                    let r = sext(self.tcx, r, ity);
 
                     // Using / or %, where the left-hand argument is the smallest integer of a signed integer type and
                     // the right-hand argument is -1 always panics, even with overflow-checks disabled
@@ -751,7 +742,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
                         return None;
                     }
 
-                    let zext = |n: i128| Constant::Int(unsext(self.lcx.tcx, n, ity));
+                    let zext = |n: i128| Constant::Int(unsext(self.tcx, n, ity));
                     match op.node {
                         // When +, * or binary - create a value greater than the maximum value, or less than
                         // the minimum value that can be stored, it panics.
@@ -845,7 +836,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
     }
 }
 
-pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Option<Constant<'tcx>> {
+pub fn mir_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::Const<'tcx>) -> Option<Constant<'tcx>> {
     let mir::Const::Val(val, _) = result else {
         // We only work on evaluated consts.
         return None;
@@ -863,13 +854,13 @@ pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) ->
             _ => None,
         },
         (_, ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Str) => {
-            let data = val.try_get_slice_bytes_for_diagnostics(lcx.tcx)?;
+            let data = val.try_get_slice_bytes_for_diagnostics(tcx)?;
             String::from_utf8(data.to_owned()).ok().map(Constant::Str)
         },
         (_, ty::Adt(adt_def, _)) if adt_def.is_struct() => Some(Constant::Adt(result)),
         (ConstValue::Indirect { alloc_id, offset }, ty::Array(sub_type, len)) => {
-            let alloc = lcx.tcx.global_alloc(alloc_id).unwrap_memory().inner();
-            let len = len.try_to_target_usize(lcx.tcx)?;
+            let alloc = tcx.global_alloc(alloc_id).unwrap_memory().inner();
+            let len = len.try_to_target_usize(tcx)?;
             let ty::Float(flt) = sub_type.kind() else {
                 return None;
             };
@@ -877,7 +868,7 @@ pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) ->
             let mut res = Vec::new();
             for idx in 0..len {
                 let range = alloc_range(offset + size * idx, size);
-                let val = alloc.read_scalar(&lcx.tcx, range, /* read_provenance */ false).ok()?;
+                let val = alloc.read_scalar(&tcx, range, /* read_provenance */ false).ok()?;
                 res.push(match flt {
                     FloatTy::F16 => Constant::F16(f16::from_bits(val.to_u16().ok()?)),
                     FloatTy::F32 => Constant::F32(f32::from_bits(val.to_u32().ok()?)),
@@ -891,7 +882,7 @@ pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) ->
     }
 }
 
-fn mir_is_empty<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Option<bool> {
+fn mir_is_empty<'tcx>(tcx: TyCtxt<'tcx>, result: mir::Const<'tcx>) -> Option<bool> {
     let mir::Const::Val(val, _) = result else {
         // We only work on evaluated consts.
         return None;
@@ -902,26 +893,26 @@ fn mir_is_empty<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Opti
                 if let ConstValue::Indirect { alloc_id, offset } = val {
                     // Get the length from the slice, using the same formula as
                     // [`ConstValue::try_get_slice_bytes_for_diagnostics`].
-                    let a = lcx.tcx.global_alloc(alloc_id).unwrap_memory().inner();
-                    let ptr_size = lcx.tcx.data_layout.pointer_size;
+                    let a = tcx.global_alloc(alloc_id).unwrap_memory().inner();
+                    let ptr_size = tcx.data_layout.pointer_size;
                     if a.size() < offset + 2 * ptr_size {
                         // (partially) dangling reference
                         return None;
                     }
                     let len = a
-                        .read_scalar(&lcx.tcx, alloc_range(offset + ptr_size, ptr_size), false)
+                        .read_scalar(&tcx, alloc_range(offset + ptr_size, ptr_size), false)
                         .ok()?
-                        .to_target_usize(&lcx.tcx)
+                        .to_target_usize(&tcx)
                         .ok()?;
                     Some(len == 0)
                 } else {
                     None
                 }
             },
-            ty::Array(_, len) => Some(len.try_to_target_usize(lcx.tcx)? == 0),
+            ty::Array(_, len) => Some(len.try_to_target_usize(tcx)? == 0),
             _ => None,
         },
-        (ConstValue::Indirect { .. }, ty::Array(_, len)) => Some(len.try_to_target_usize(lcx.tcx)? == 0),
+        (ConstValue::Indirect { .. }, ty::Array(_, len)) => Some(len.try_to_target_usize(tcx)? == 0),
         (ConstValue::ZeroSized, _) => Some(true),
         _ => None,
     }
@@ -929,12 +920,12 @@ fn mir_is_empty<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Opti
 
 fn field_of_struct<'tcx>(
     adt_def: ty::AdtDef<'tcx>,
-    lcx: &LateContext<'tcx>,
+    tcx: TyCtxt<'tcx>,
     result: mir::Const<'tcx>,
     field: &Ident,
 ) -> Option<mir::Const<'tcx>> {
     if let mir::Const::Val(result, ty) = result
-        && let Some(dc) = lcx.tcx.try_destructure_mir_constant_for_user_output(result, ty)
+        && let Some(dc) = tcx.try_destructure_mir_constant_for_user_output(result, ty)
         && let Some(dc_variant) = dc.variant
         && let Some(variant) = adt_def.variants().get(dc_variant)
         && let Some(field_idx) = variant.fields.iter().position(|el| el.name == field.name)
diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs
index 0641d37cd9a..4877fb65d37 100644
--- a/src/tools/clippy/clippy_utils/src/diagnostics.rs
+++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs
@@ -330,32 +330,3 @@ pub fn span_lint_and_sugg<T: LintContext>(
         diag.span_suggestion(sp, help.into(), sugg, applicability);
     });
 }
-
-/// Create a suggestion made from several `span → replacement`.
-///
-/// Note: in the JSON format (used by `compiletest_rs`), the help message will
-/// appear once per
-/// replacement. In human-readable format though, it only appears once before
-/// the whole suggestion.
-pub fn multispan_sugg<I>(diag: &mut Diag<'_, ()>, help_msg: impl Into<SubdiagMessage>, sugg: I)
-where
-    I: IntoIterator<Item = (Span, String)>,
-{
-    multispan_sugg_with_applicability(diag, help_msg, Applicability::Unspecified, sugg);
-}
-
-/// Create a suggestion made from several `span → replacement`.
-///
-/// rustfix currently doesn't support the automatic application of suggestions with
-/// multiple spans. This is tracked in issue [rustfix#141](https://github.com/rust-lang/rustfix/issues/141).
-/// Suggestions with multiple spans will be silently ignored.
-pub fn multispan_sugg_with_applicability<I>(
-    diag: &mut Diag<'_, ()>,
-    help_msg: impl Into<SubdiagMessage>,
-    applicability: Applicability,
-    sugg: I,
-) where
-    I: IntoIterator<Item = (Span, String)>,
-{
-    diag.multipart_suggestion(help_msg.into(), sugg.into_iter().collect(), applicability);
-}
diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
index 6c40029a9de..a6dd12a28c5 100644
--- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
+++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
@@ -9,7 +9,7 @@
 //!  - or-fun-call
 //!  - option-if-let-else
 
-use crate::consts::{constant, FullInt};
+use crate::consts::{ConstEvalCtxt, FullInt};
 use crate::ty::{all_predicates_of, is_copy};
 use crate::visitors::is_const_evaluatable;
 use rustc_hir::def::{DefKind, Res};
@@ -206,7 +206,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
                 },
 
                 // `-i32::MIN` panics with overflow checks
-                ExprKind::Unary(UnOp::Neg, right) if constant(self.cx, self.cx.typeck_results(), right).is_none() => {
+                ExprKind::Unary(UnOp::Neg, right) if ConstEvalCtxt::new(self.cx).eval(right).is_none() => {
                     self.eagerness |= NoChange;
                 },
 
@@ -232,7 +232,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
                 // Thus, we would realistically only delay the lint.
                 ExprKind::Binary(op, _, right)
                     if matches!(op.node, BinOpKind::Shl | BinOpKind::Shr)
-                        && constant(self.cx, self.cx.typeck_results(), right).is_none() =>
+                        && ConstEvalCtxt::new(self.cx).eval(right).is_none() =>
                 {
                     self.eagerness |= NoChange;
                 },
@@ -240,9 +240,9 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
                 ExprKind::Binary(op, left, right)
                     if matches!(op.node, BinOpKind::Div | BinOpKind::Rem)
                         && let right_ty = self.cx.typeck_results().expr_ty(right)
-                        && let left = constant(self.cx, self.cx.typeck_results(), left)
-                        && let right = constant(self.cx, self.cx.typeck_results(), right)
-                            .and_then(|c| c.int_value(self.cx, right_ty))
+                        && let ecx = ConstEvalCtxt::new(self.cx)
+                        && let left = ecx.eval(left)
+                        && let right = ecx.eval(right).and_then(|c| c.int_value(self.cx.tcx, right_ty))
                         && matches!(
                             (left, right),
                             // `1 / x`: x might be zero
@@ -261,8 +261,8 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
                 ExprKind::Binary(op, left, right)
                     if matches!(op.node, BinOpKind::Add | BinOpKind::Sub | BinOpKind::Mul)
                         && !self.cx.typeck_results().expr_ty(e).is_floating_point()
-                        && (constant(self.cx, self.cx.typeck_results(), left).is_none()
-                            || constant(self.cx, self.cx.typeck_results(), right).is_none()) =>
+                        && let ecx = ConstEvalCtxt::new(self.cx)
+                        && (ecx.eval(left).is_none() || ecx.eval(right).is_none()) =>
                 {
                     self.eagerness |= NoChange;
                 },
diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs
index 277ba8427e0..8970b4d1229 100644
--- a/src/tools/clippy/clippy_utils/src/higher.rs
+++ b/src/tools/clippy/clippy_utils/src/higher.rs
@@ -2,7 +2,7 @@
 
 #![deny(clippy::missing_docs_in_private_items)]
 
-use crate::consts::{constant_simple, Constant};
+use crate::consts::{ConstEvalCtxt, Constant};
 use crate::ty::is_type_diagnostic_item;
 use crate::{is_expn_of, match_def_path, paths};
 
@@ -25,6 +25,8 @@ pub struct ForLoop<'tcx> {
     pub loop_id: HirId,
     /// entire `for` loop span
     pub span: Span,
+    /// label
+    pub label: Option<ast::Label>,
 }
 
 impl<'tcx> ForLoop<'tcx> {
@@ -33,7 +35,7 @@ impl<'tcx> ForLoop<'tcx> {
         if let ExprKind::DropTemps(e) = expr.kind
             && let ExprKind::Match(iterexpr, [arm], MatchSource::ForLoopDesugar) = e.kind
             && let ExprKind::Call(_, [arg]) = iterexpr.kind
-            && let ExprKind::Loop(block, ..) = arm.body.kind
+            && let ExprKind::Loop(block, label, ..) = arm.body.kind
             && let [stmt] = block.stmts
             && let hir::StmtKind::Expr(e) = stmt.kind
             && let ExprKind::Match(_, [_, some_arm], _) = e.kind
@@ -45,6 +47,7 @@ impl<'tcx> ForLoop<'tcx> {
                 body: some_arm.body,
                 loop_id: arm.body.hir_id,
                 span: expr.span.ctxt().outer_expn_data().call_site,
+                label,
             });
         }
         None
@@ -367,6 +370,7 @@ pub struct WhileLet<'hir> {
     pub let_expr: &'hir Expr<'hir>,
     /// `while let` loop body
     pub if_then: &'hir Expr<'hir>,
+    pub label: Option<ast::Label>,
     /// `while let PAT = EXPR`
     ///        ^^^^^^^^^^^^^^
     pub let_span: Span,
@@ -399,7 +403,7 @@ impl<'hir> WhileLet<'hir> {
                     }),
                 ..
             },
-            _,
+            label,
             LoopSource::While,
             _,
         ) = expr.kind
@@ -408,6 +412,7 @@ impl<'hir> WhileLet<'hir> {
                 let_pat,
                 let_expr,
                 if_then,
+                label,
                 let_span,
             });
         }
@@ -466,7 +471,7 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -
                     return Some(VecInitKind::Default);
                 } else if name.ident.name.as_str() == "with_capacity" {
                     let arg = args.first()?;
-                    return match constant_simple(cx, cx.typeck_results(), arg) {
+                    return match ConstEvalCtxt::new(cx).eval_simple(arg) {
                         Some(Constant::Int(num)) => Some(VecInitKind::WithConstCapacity(num)),
                         _ => Some(VecInitKind::WithExprCapacity(arg.hir_id)),
                     };
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 28178a61a93..f325e4eaf15 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -1,4 +1,4 @@
-use crate::consts::constant_simple;
+use crate::consts::ConstEvalCtxt;
 use crate::macros::macro_backtrace;
 use crate::source::{snippet_opt, walk_span_to_context, SpanRange, SpanRangeExt};
 use crate::tokenize_with_text;
@@ -255,8 +255,8 @@ impl HirEqInterExpr<'_, '_, '_> {
         if let Some((typeck_lhs, typeck_rhs)) = self.inner.maybe_typeck_results
             && typeck_lhs.expr_ty(left) == typeck_rhs.expr_ty(right)
             && let (Some(l), Some(r)) = (
-                constant_simple(self.inner.cx, typeck_lhs, left),
-                constant_simple(self.inner.cx, typeck_rhs, right),
+                ConstEvalCtxt::with_env(self.inner.cx.tcx, self.inner.cx.param_env, typeck_lhs).eval_simple(left),
+                ConstEvalCtxt::with_env(self.inner.cx.tcx, self.inner.cx.param_env, typeck_rhs).eval_simple(right),
             )
             && l == r
         {
@@ -714,9 +714,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
 
     #[expect(clippy::too_many_lines)]
     pub fn hash_expr(&mut self, e: &Expr<'_>) {
-        let simple_const = self
-            .maybe_typeck_results
-            .and_then(|typeck_results| constant_simple(self.cx, typeck_results, e));
+        let simple_const = self.maybe_typeck_results.and_then(|typeck_results| {
+            ConstEvalCtxt::with_env(self.cx.tcx, self.cx.param_env, typeck_results).eval_simple(e)
+        });
 
         // const hashing may result in the same hash as some unrelated node, so add a sort of
         // discriminant depending on which path we're choosing next
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 3a9714c49ae..28755ae0710 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -5,13 +5,11 @@
 #![feature(f16)]
 #![feature(if_let_guard)]
 #![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(lint_reasons))]
 #![feature(never_type)]
 #![feature(rustc_private)]
 #![feature(assert_matches)]
 #![feature(unwrap_infallible)]
 #![recursion_limit = "512"]
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![allow(
     clippy::missing_errors_doc,
     clippy::missing_panics_doc,
@@ -127,7 +125,7 @@ use rustc_span::{sym, Span};
 use rustc_target::abi::Integer;
 use visitors::Visitable;
 
-use crate::consts::{constant, mir_to_const, Constant};
+use crate::consts::{mir_to_const, ConstEvalCtxt, Constant};
 use crate::higher::Range;
 use crate::ty::{adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type};
 use crate::visitors::for_each_expr_without_closures;
@@ -212,20 +210,24 @@ pub fn local_is_initialized(cx: &LateContext<'_>, local: HirId) -> bool {
     false
 }
 
-/// Returns `true` if the given `HirId` is inside a constant context.
+/// Checks if we are currently in a const context (e.g. `const fn`, `static`/`const` initializer).
 ///
-/// This is the same as `is_inside_always_const_context`, but also includes
-/// `const fn`.
+/// The current context is determined based on the current body which is set before calling a lint's
+/// entry point (any function on `LateLintPass`). If you need to check in a different context use
+/// `tcx.hir().is_inside_const_context(_)`.
 ///
-/// # Example
-///
-/// ```rust,ignore
-/// if in_constant(cx, expr.hir_id) {
-///     // Do something
-/// }
-/// ```
-pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool {
-    cx.tcx.hir().is_inside_const_context(id)
+/// Do not call this unless the `LateContext` has an enclosing body. For release build this case
+/// will safely return `false`, but debug builds will ICE. Note that `check_expr`, `check_block`,
+/// `check_pat` and a few other entry points will always have an enclosing body. Some entry points
+/// like `check_path` or `check_ty` may or may not have one.
+pub fn is_in_const_context(cx: &LateContext<'_>) -> bool {
+    debug_assert!(cx.enclosing_body.is_some(), "`LateContext` has no enclosing body");
+    cx.enclosing_body.is_some_and(|id| {
+        cx.tcx
+            .hir()
+            .body_const_context(cx.tcx.hir().body_owner_def_id(id))
+            .is_some()
+    })
 }
 
 /// Returns `true` if the given `HirId` is inside an always constant context.
@@ -590,9 +592,8 @@ fn find_primitive_impls<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator<It
         "u128" => SimplifiedType::Uint(UintTy::U128),
         "f32" => SimplifiedType::Float(FloatTy::F32),
         "f64" => SimplifiedType::Float(FloatTy::F64),
-        #[allow(trivial_casts)]
         _ => {
-            return Result::<_, rustc_errors::ErrorGuaranteed>::Ok(&[] as &[_])
+            return Result::<&[_], rustc_errors::ErrorGuaranteed>::Ok(&[])
                 .into_iter()
                 .flatten()
                 .copied();
@@ -1580,8 +1581,8 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti
             if let rustc_ty::Adt(_, subst) = ty.kind()
                 && let bnd_ty = subst.type_at(0)
                 && let Some(min_val) = bnd_ty.numeric_min_val(cx.tcx)
-                && let Some(min_const) = mir_to_const(cx, Const::from_ty_const(min_val, bnd_ty, cx.tcx))
-                && let Some(start_const) = constant(cx, cx.typeck_results(), start)
+                && let Some(min_const) = mir_to_const(cx.tcx, Const::from_ty_const(min_val, bnd_ty, cx.tcx))
+                && let Some(start_const) = ConstEvalCtxt::new(cx).eval(start)
             {
                 start_const == min_const
             } else {
@@ -1593,8 +1594,8 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti
                 if let rustc_ty::Adt(_, subst) = ty.kind()
                     && let bnd_ty = subst.type_at(0)
                     && let Some(max_val) = bnd_ty.numeric_max_val(cx.tcx)
-                    && let Some(max_const) = mir_to_const(cx, Const::from_ty_const(max_val, bnd_ty, cx.tcx))
-                    && let Some(end_const) = constant(cx, cx.typeck_results(), end)
+                    && let Some(max_const) = mir_to_const(cx.tcx, Const::from_ty_const(max_val, bnd_ty, cx.tcx))
+                    && let Some(end_const) = ConstEvalCtxt::new(cx).eval(end)
                 {
                     end_const == max_const
                 } else {
@@ -1625,7 +1626,9 @@ pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool
         return true;
     }
     let enclosing_body = cx.tcx.hir().enclosing_body_owner(e.hir_id);
-    if let Some(Constant::Int(v)) = constant(cx, cx.tcx.typeck(enclosing_body), e) {
+    if let Some(Constant::Int(v)) =
+        ConstEvalCtxt::with_env(cx.tcx, cx.tcx.param_env(enclosing_body), cx.tcx.typeck(enclosing_body)).eval(e)
+    {
         return value == v;
     }
     false
@@ -2928,6 +2931,7 @@ pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> ExprU
             moved_before_use,
             same_ctxt,
         },
+        #[allow(unreachable_patterns)]
         Some(ControlFlow::Break(_)) => unreachable!("type of node is ControlFlow<!>"),
         None => ExprUseCtxt {
             node: Node::Crate(cx.tcx.hir().root_module()),
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index d5a3d8b9e5a..684c645c199 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -16,7 +16,6 @@ pub const BINARYHEAP_ITER: [&str; 5] = ["alloc", "collections", "binary_heap", "
 pub const BTREEMAP_CONTAINS_KEY: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "contains_key"];
 pub const BTREEMAP_INSERT: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "insert"];
 pub const BTREESET_ITER: [&str; 6] = ["alloc", "collections", "btree", "set", "BTreeSet", "iter"];
-pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"];
 pub const CORE_ITER_CLONED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "cloned"];
 pub const CORE_ITER_COPIED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "copied"];
 pub const CORE_ITER_FILTER: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "filter"];
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 f206b2ceebc..553af913ef9 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
@@ -142,7 +142,7 @@ fn check_rvalue<'tcx>(
                 // We cannot allow this for now.
                 return Err((span, "unsizing casts are only allowed for references right now".into()));
             };
-            let unsized_ty = tcx.struct_tail_erasing_lifetimes(pointee_ty, tcx.param_env(def_id));
+            let unsized_ty = tcx.struct_tail_for_codegen(pointee_ty, tcx.param_env(def_id));
             if let ty::Slice(_) | ty::Str = unsized_ty.kind() {
                 check_operand(tcx, op, span, body, msrv)?;
                 // Casting/coercing things to slices is fine.
diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs
index 496c8f5b553..96dd3c55d37 100644
--- a/src/tools/clippy/clippy_utils/src/source.rs
+++ b/src/tools/clippy/clippy_utils/src/source.rs
@@ -6,7 +6,8 @@ use rustc_ast::{LitKind, StrStyle};
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::Applicability;
 use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource};
-use rustc_lint::{LateContext, LintContext};
+use rustc_lint::{EarlyContext, LateContext};
+use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_span::source_map::{original_sp, SourceMap};
 use rustc_span::{
@@ -17,6 +18,30 @@ use std::borrow::Cow;
 use std::fmt;
 use std::ops::Range;
 
+pub trait HasSession {
+    fn sess(&self) -> &Session;
+}
+impl HasSession for Session {
+    fn sess(&self) -> &Session {
+        self
+    }
+}
+impl HasSession for TyCtxt<'_> {
+    fn sess(&self) -> &Session {
+        self.sess
+    }
+}
+impl HasSession for EarlyContext<'_> {
+    fn sess(&self) -> &Session {
+        ::rustc_lint::LintContext::sess(self)
+    }
+}
+impl HasSession for LateContext<'_> {
+    fn sess(&self) -> &Session {
+        self.tcx.sess()
+    }
+}
+
 /// Conversion of a value into the range portion of a `Span`.
 pub trait SpanRange: Sized {
     fn into_range(self) -> Range<BytePos>;
@@ -71,19 +96,19 @@ impl IntoSpan for Range<BytePos> {
 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> {
+    fn get_source_text(self, cx: &impl HasSession) -> 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> {
+    fn with_source_text<T>(self, cx: &impl HasSession, 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 {
+    fn check_source_text(self, cx: &impl HasSession, pred: impl for<'a> FnOnce(&'a str) -> bool) -> bool {
         self.with_source_text(cx, pred).unwrap_or(false)
     }
 
@@ -91,7 +116,7 @@ pub trait SpanRangeExt: SpanRange {
     /// and returns the value. Returns `None` if the source text cannot be retrieved.
     fn with_source_text_and_range<T>(
         self,
-        cx: &impl LintContext,
+        cx: &impl HasSession,
         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)
@@ -104,30 +129,30 @@ pub trait SpanRangeExt: SpanRange {
     /// The new range must reside within the same source file.
     fn map_range(
         self,
-        cx: &impl LintContext,
+        cx: &impl HasSession,
         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> {
+    fn with_leading_whitespace(self, cx: &impl HasSession) -> 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> {
+    fn trim_start(self, cx: &impl HasSession) -> 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 {
+    fn write_source_text_to(self, cx: &impl HasSession, 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> {
+    fn source_text_to_string(self, cx: &impl HasSession) -> Option<String> {
         self.with_source_text(cx, ToOwned::to_owned)
     }
 }
@@ -227,15 +252,15 @@ impl SourceFileRange {
 }
 
 /// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`.
-pub fn expr_block<T: LintContext>(
-    cx: &T,
+pub fn expr_block(
+    sess: &impl HasSession,
     expr: &Expr<'_>,
     outer: SyntaxContext,
     default: &str,
     indent_relative_to: Option<Span>,
     app: &mut Applicability,
 ) -> String {
-    let (code, from_macro) = snippet_block_with_context(cx, expr.span, outer, default, indent_relative_to, app);
+    let (code, from_macro) = snippet_block_with_context(sess, expr.span, outer, default, indent_relative_to, app);
     if !from_macro
         && let ExprKind::Block(block, _) = expr.kind
         && block.rules != BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
@@ -260,13 +285,13 @@ pub fn expr_block<T: LintContext>(
 ///     let x = ();
 /// //  ^^^^^^^^^^
 /// ```
-pub fn first_line_of_span<T: LintContext>(cx: &T, span: Span) -> Span {
-    first_char_in_first_line(cx, span).map_or(span, |first_char_pos| span.with_lo(first_char_pos))
+pub fn first_line_of_span(sess: &impl HasSession, span: Span) -> Span {
+    first_char_in_first_line(sess, span).map_or(span, |first_char_pos| span.with_lo(first_char_pos))
 }
 
-fn first_char_in_first_line<T: LintContext>(cx: &T, span: Span) -> Option<BytePos> {
-    let line_span = line_span(cx, span);
-    snippet_opt(cx, line_span).and_then(|snip| {
+fn first_char_in_first_line(sess: &impl HasSession, span: Span) -> Option<BytePos> {
+    let line_span = line_span(sess, span);
+    snippet_opt(sess, line_span).and_then(|snip| {
         snip.find(|c: char| !c.is_whitespace())
             .map(|pos| line_span.lo() + BytePos::from_usize(pos))
     })
@@ -281,9 +306,9 @@ fn first_char_in_first_line<T: LintContext>(cx: &T, span: Span) -> Option<BytePo
 ///        let x = ();
 /// // ^^^^^^^^^^^^^^
 /// ```
-fn line_span<T: LintContext>(cx: &T, span: Span) -> Span {
+fn line_span(sess: &impl HasSession, span: Span) -> Span {
     let span = original_sp(span, DUMMY_SP);
-    let SourceFileAndLine { sf, line } = cx.sess().source_map().lookup_line(span.lo()).unwrap();
+    let SourceFileAndLine { sf, line } = sess.sess().source_map().lookup_line(span.lo()).unwrap();
     let line_start = sf.lines()[line];
     let line_start = sf.absolute_position(line_start);
     span.with_lo(line_start)
@@ -297,13 +322,13 @@ fn line_span<T: LintContext>(cx: &T, span: Span) -> Span {
 ///     let x = ();
 /// //          ^^ -- will return 4
 /// ```
-pub fn indent_of<T: LintContext>(cx: &T, span: Span) -> Option<usize> {
-    snippet_opt(cx, line_span(cx, span)).and_then(|snip| snip.find(|c: char| !c.is_whitespace()))
+pub fn indent_of(sess: &impl HasSession, span: Span) -> Option<usize> {
+    snippet_opt(sess, line_span(sess, span)).and_then(|snip| snip.find(|c: char| !c.is_whitespace()))
 }
 
 /// Gets a snippet of the indentation of the line of a span
-pub fn snippet_indent<T: LintContext>(cx: &T, span: Span) -> Option<String> {
-    snippet_opt(cx, line_span(cx, span)).map(|mut s| {
+pub fn snippet_indent(sess: &impl HasSession, span: Span) -> Option<String> {
+    snippet_opt(sess, line_span(sess, span)).map(|mut s| {
         let len = s.len() - s.trim_start().len();
         s.truncate(len);
         s
@@ -315,8 +340,8 @@ pub fn snippet_indent<T: LintContext>(cx: &T, span: Span) -> Option<String> {
 // sources that the user has no control over.
 // For some reason these attributes don't have any expansion info on them, so
 // we have to check it this way until there is a better way.
-pub fn is_present_in_source<T: LintContext>(cx: &T, span: Span) -> bool {
-    if let Some(snippet) = snippet_opt(cx, span) {
+pub fn is_present_in_source(sess: &impl HasSession, span: Span) -> bool {
+    if let Some(snippet) = snippet_opt(sess, span) {
         if snippet.is_empty() {
             return false;
         }
@@ -407,8 +432,8 @@ fn reindent_multiline_inner(s: &str, ignore_first: bool, indent: Option<usize>,
 /// snippet(cx, span1, "..") // -> "value"
 /// snippet(cx, span2, "..") // -> "Vec::new()"
 /// ```
-pub fn snippet<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> {
-    snippet_opt(cx, span).map_or_else(|| Cow::Borrowed(default), From::from)
+pub fn snippet<'a>(sess: &impl HasSession, span: Span, default: &'a str) -> Cow<'a, str> {
+    snippet_opt(sess, span).map_or_else(|| Cow::Borrowed(default), From::from)
 }
 
 /// Same as [`snippet`], but it adapts the applicability level by following rules:
@@ -417,13 +442,13 @@ pub fn snippet<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<
 /// - If the span is inside a macro, change the applicability level to `MaybeIncorrect`.
 /// - If the default value is used and the applicability level is `MachineApplicable`, change it to
 ///   `HasPlaceholders`
-pub fn snippet_with_applicability<'a, T: LintContext>(
-    cx: &T,
+pub fn snippet_with_applicability<'a>(
+    sess: &impl HasSession,
     span: Span,
     default: &'a str,
     applicability: &mut Applicability,
 ) -> Cow<'a, str> {
-    snippet_with_applicability_sess(cx.sess(), span, default, applicability)
+    snippet_with_applicability_sess(sess.sess(), span, default, applicability)
 }
 
 fn snippet_with_applicability_sess<'a>(
@@ -435,7 +460,7 @@ fn snippet_with_applicability_sess<'a>(
     if *applicability != Applicability::Unspecified && span.from_expansion() {
         *applicability = Applicability::MaybeIncorrect;
     }
-    snippet_opt_sess(sess, span).map_or_else(
+    snippet_opt(sess, span).map_or_else(
         || {
             if *applicability == Applicability::MachineApplicable {
                 *applicability = Applicability::HasPlaceholders;
@@ -447,12 +472,8 @@ fn snippet_with_applicability_sess<'a>(
 }
 
 /// Converts a span to a code snippet. Returns `None` if not available.
-pub fn snippet_opt(cx: &impl LintContext, span: Span) -> Option<String> {
-    snippet_opt_sess(cx.sess(), span)
-}
-
-fn snippet_opt_sess(sess: &Session, span: Span) -> Option<String> {
-    sess.source_map().span_to_snippet(span).ok()
+pub fn snippet_opt(sess: &impl HasSession, span: Span) -> Option<String> {
+    sess.sess().source_map().span_to_snippet(span).ok()
 }
 
 /// Converts a span (from a block) to a code snippet if available, otherwise use default.
@@ -489,41 +510,41 @@ fn snippet_opt_sess(sess: &Session, span: Span) -> Option<String> {
 ///     } // aligned with `if`
 /// ```
 /// Note that the first line of the snippet always has 0 indentation.
-pub fn snippet_block<'a, T: LintContext>(
-    cx: &T,
+pub fn snippet_block<'a>(
+    sess: &impl HasSession,
     span: Span,
     default: &'a str,
     indent_relative_to: Option<Span>,
 ) -> Cow<'a, str> {
-    let snip = snippet(cx, span, default);
-    let indent = indent_relative_to.and_then(|s| indent_of(cx, s));
+    let snip = snippet(sess, span, default);
+    let indent = indent_relative_to.and_then(|s| indent_of(sess, s));
     reindent_multiline(snip, true, indent)
 }
 
 /// Same as `snippet_block`, but adapts the applicability level by the rules of
 /// `snippet_with_applicability`.
 pub fn snippet_block_with_applicability<'a>(
-    cx: &impl LintContext,
+    sess: &impl HasSession,
     span: Span,
     default: &'a str,
     indent_relative_to: Option<Span>,
     applicability: &mut Applicability,
 ) -> Cow<'a, str> {
-    let snip = snippet_with_applicability(cx, span, default, applicability);
-    let indent = indent_relative_to.and_then(|s| indent_of(cx, s));
+    let snip = snippet_with_applicability(sess, span, default, applicability);
+    let indent = indent_relative_to.and_then(|s| indent_of(sess, s));
     reindent_multiline(snip, true, indent)
 }
 
 pub fn snippet_block_with_context<'a>(
-    cx: &impl LintContext,
+    sess: &impl HasSession,
     span: Span,
     outer: SyntaxContext,
     default: &'a str,
     indent_relative_to: Option<Span>,
     app: &mut Applicability,
 ) -> (Cow<'a, str>, bool) {
-    let (snip, from_macro) = snippet_with_context(cx, span, outer, default, app);
-    let indent = indent_relative_to.and_then(|s| indent_of(cx, s));
+    let (snip, from_macro) = snippet_with_context(sess, span, outer, default, app);
+    let indent = indent_relative_to.and_then(|s| indent_of(sess, s));
     (reindent_multiline(snip, true, indent), from_macro)
 }
 
@@ -537,13 +558,13 @@ pub fn snippet_block_with_context<'a>(
 ///
 /// This will also return whether or not the snippet is a macro call.
 pub fn snippet_with_context<'a>(
-    cx: &impl LintContext,
+    sess: &impl HasSession,
     span: Span,
     outer: SyntaxContext,
     default: &'a str,
     applicability: &mut Applicability,
 ) -> (Cow<'a, str>, bool) {
-    snippet_with_context_sess(cx.sess(), span, outer, default, applicability)
+    snippet_with_context_sess(sess.sess(), span, outer, default, applicability)
 }
 
 fn snippet_with_context_sess<'a>(
@@ -661,15 +682,15 @@ pub fn trim_span(sm: &SourceMap, span: Span) -> Span {
 /// writeln!(o, "")   ->   writeln!(o, "")
 ///             ^^                   ^^^^
 /// ```
-pub fn expand_past_previous_comma(cx: &LateContext<'_>, span: Span) -> Span {
-    let extended = cx.sess().source_map().span_extend_to_prev_char(span, ',', true);
+pub fn expand_past_previous_comma(sess: &impl HasSession, span: Span) -> Span {
+    let extended = sess.sess().source_map().span_extend_to_prev_char(span, ',', true);
     extended.with_lo(extended.lo() - BytePos(1))
 }
 
 /// Converts `expr` to a `char` literal if it's a `str` literal containing a single
 /// character (or a single byte with `ascii_only`)
 pub fn str_literal_to_char_literal(
-    cx: &LateContext<'_>,
+    sess: &impl HasSession,
     expr: &Expr<'_>,
     applicability: &mut Applicability,
     ascii_only: bool,
@@ -684,7 +705,7 @@ pub fn str_literal_to_char_literal(
         }
         && len == 1
     {
-        let snip = snippet_with_applicability(cx, expr.span, string, applicability);
+        let snip = snippet_with_applicability(sess, expr.span, string, applicability);
         let ch = if let StrStyle::Raw(nhash) = style {
             let nhash = nhash as usize;
             // for raw string: r##"a"##
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 812fb647fda..bd48990aea9 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -525,19 +525,6 @@ pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
     needs_ordered_drop_inner(cx, ty, &mut FxHashSet::default())
 }
 
-/// Peels off all references on the type. Returns the underlying type and the number of references
-/// removed.
-pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) {
-    fn peel(ty: Ty<'_>, count: usize) -> (Ty<'_>, usize) {
-        if let ty::Ref(_, ty, _) = ty.kind() {
-            peel(*ty, count + 1)
-        } else {
-            (ty, count)
-        }
-    }
-    peel(ty, 0)
-}
-
 /// Peels off all references on the type. Returns the underlying type, the number of references
 /// removed, and whether the pointer is ultimately mutable or not.
 pub fn peel_mid_ty_refs_is_mutable(ty: Ty<'_>) -> (Ty<'_>, usize, Mutability) {
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index 7066c9ad2b9..2a5d3536ff6 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -1,6 +1,7 @@
 use crate::ty::needs_ordered_drop;
 use crate::{get_enclosing_block, path_to_local_id};
 use core::ops::ControlFlow;
+use rustc_ast::visit::{try_visit, VisitorResult};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::intravisit::{self, walk_block, walk_expr, Visitor};
@@ -50,16 +51,17 @@ impl Continue for Descend {
 /// A type which can be visited.
 pub trait Visitable<'tcx> {
     /// Calls the corresponding `visit_*` function on the visitor.
-    fn visit<V: Visitor<'tcx>>(self, visitor: &mut V);
+    fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) -> V::Result;
 }
 impl<'tcx, T> Visitable<'tcx> for &'tcx [T]
 where
     &'tcx T: Visitable<'tcx>,
 {
-    fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) {
+    fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) -> V::Result {
         for x in self {
-            x.visit(visitor);
+            try_visit!(x.visit(visitor));
         }
+        V::Result::output()
     }
 }
 impl<'tcx, A, B> Visitable<'tcx> for (A, B)
@@ -67,27 +69,28 @@ where
     A: Visitable<'tcx>,
     B: Visitable<'tcx>,
 {
-    fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) {
+    fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) -> V::Result {
         let (a, b) = self;
-        a.visit(visitor);
-        b.visit(visitor);
+        try_visit!(a.visit(visitor));
+        b.visit(visitor)
     }
 }
 impl<'tcx, T> Visitable<'tcx> for Option<T>
 where
     T: Visitable<'tcx>,
 {
-    fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) {
+    fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) -> V::Result {
         if let Some(x) = self {
-            x.visit(visitor);
+            try_visit!(x.visit(visitor));
         }
+        V::Result::output()
     }
 }
 macro_rules! visitable_ref {
     ($t:ident, $f:ident) => {
         impl<'tcx> Visitable<'tcx> for &'tcx $t<'tcx> {
-            fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) {
-                visitor.$f(self);
+            fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) -> V::Result {
+                visitor.$f(self)
             }
         }
     };
@@ -104,45 +107,37 @@ pub fn for_each_expr_without_closures<'tcx, B, C: Continue>(
     node: impl Visitable<'tcx>,
     f: impl FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B, C>,
 ) -> Option<B> {
-    struct V<B, F> {
+    struct V<F> {
         f: F,
-        res: Option<B>,
     }
-    impl<'tcx, B, C: Continue, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B, C>> Visitor<'tcx> for V<B, F> {
-        type Result = ControlFlow<()>;
+    impl<'tcx, B, C: Continue, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B, C>> Visitor<'tcx> for V<F> {
+        type Result = ControlFlow<B>;
 
-        fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) -> ControlFlow<()> {
-            if self.res.is_some() {
-                return ControlFlow::Break(());
-            }
+        fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) -> Self::Result {
             match (self.f)(e) {
                 ControlFlow::Continue(c) if c.descend() => walk_expr(self, e),
-                ControlFlow::Break(b) => {
-                    self.res = Some(b);
-                    ControlFlow::Break(())
-                },
+                ControlFlow::Break(b) => ControlFlow::Break(b),
                 ControlFlow::Continue(_) => ControlFlow::Continue(()),
             }
         }
 
         // Avoid unnecessary `walk_*` calls.
-        fn visit_ty(&mut self, _: &'tcx hir::Ty<'tcx>) -> ControlFlow<()> {
+        fn visit_ty(&mut self, _: &'tcx hir::Ty<'tcx>) -> Self::Result {
             ControlFlow::Continue(())
         }
-        fn visit_pat(&mut self, _: &'tcx Pat<'tcx>) -> ControlFlow<()> {
+        fn visit_pat(&mut self, _: &'tcx Pat<'tcx>) -> Self::Result {
             ControlFlow::Continue(())
         }
-        fn visit_qpath(&mut self, _: &'tcx QPath<'tcx>, _: HirId, _: Span) -> ControlFlow<()> {
+        fn visit_qpath(&mut self, _: &'tcx QPath<'tcx>, _: HirId, _: Span) -> Self::Result {
             ControlFlow::Continue(())
         }
         // Avoid monomorphising all `visit_*` functions.
-        fn visit_nested_item(&mut self, _: ItemId) -> ControlFlow<()> {
+        fn visit_nested_item(&mut self, _: ItemId) -> Self::Result {
             ControlFlow::Continue(())
         }
     }
-    let mut v = V { f, res: None };
-    node.visit(&mut v);
-    v.res
+    let mut v = V { f };
+    node.visit(&mut v).break_value()
 }
 
 /// Calls the given function once for each expression contained. This will enter bodies, but not
@@ -152,44 +147,47 @@ pub fn for_each_expr<'tcx, B, C: Continue>(
     node: impl Visitable<'tcx>,
     f: impl FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B, C>,
 ) -> Option<B> {
-    struct V<'tcx, B, F> {
+    struct V<'tcx, F> {
         tcx: TyCtxt<'tcx>,
         f: F,
-        res: Option<B>,
     }
-    impl<'tcx, B, C: Continue, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B, C>> Visitor<'tcx> for V<'tcx, B, F> {
+    impl<'tcx, B, C: Continue, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B, C>> Visitor<'tcx> for V<'tcx, F> {
         type NestedFilter = nested_filter::OnlyBodies;
+        type Result = ControlFlow<B>;
+
         fn nested_visit_map(&mut self) -> Self::Map {
             self.tcx.hir()
         }
 
-        fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) {
-            if self.res.is_some() {
-                return;
-            }
+        fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) -> Self::Result {
             match (self.f)(e) {
                 ControlFlow::Continue(c) if c.descend() => walk_expr(self, e),
-                ControlFlow::Break(b) => self.res = Some(b),
-                ControlFlow::Continue(_) => (),
+                ControlFlow::Break(b) => ControlFlow::Break(b),
+                ControlFlow::Continue(_) => ControlFlow::Continue(()),
             }
         }
 
         // Only walk closures
-        fn visit_anon_const(&mut self, _: &'tcx AnonConst) {}
+        fn visit_anon_const(&mut self, _: &'tcx AnonConst) -> Self::Result {
+            ControlFlow::Continue(())
+        }
         // Avoid unnecessary `walk_*` calls.
-        fn visit_ty(&mut self, _: &'tcx hir::Ty<'tcx>) {}
-        fn visit_pat(&mut self, _: &'tcx Pat<'tcx>) {}
-        fn visit_qpath(&mut self, _: &'tcx QPath<'tcx>, _: HirId, _: Span) {}
+        fn visit_ty(&mut self, _: &'tcx hir::Ty<'tcx>) -> Self::Result {
+            ControlFlow::Continue(())
+        }
+        fn visit_pat(&mut self, _: &'tcx Pat<'tcx>) -> Self::Result {
+            ControlFlow::Continue(())
+        }
+        fn visit_qpath(&mut self, _: &'tcx QPath<'tcx>, _: HirId, _: Span) -> Self::Result {
+            ControlFlow::Continue(())
+        }
         // Avoid monomorphising all `visit_*` functions.
-        fn visit_nested_item(&mut self, _: ItemId) {}
+        fn visit_nested_item(&mut self, _: ItemId) -> Self::Result {
+            ControlFlow::Continue(())
+        }
     }
-    let mut v = V {
-        tcx: cx.tcx,
-        f,
-        res: None,
-    };
-    node.visit(&mut v);
-    v.res
+    let mut v = V { tcx: cx.tcx, f };
+    node.visit(&mut v).break_value()
 }
 
 /// returns `true` if expr contains match expr desugared from try
diff --git a/src/tools/clippy/declare_clippy_lint/Cargo.toml b/src/tools/clippy/declare_clippy_lint/Cargo.toml
index 80106f683c2..31270241b0b 100644
--- a/src/tools/clippy/declare_clippy_lint/Cargo.toml
+++ b/src/tools/clippy/declare_clippy_lint/Cargo.toml
@@ -11,6 +11,3 @@ proc-macro = true
 itertools = "0.12"
 quote = "1.0.21"
 syn = "2.0"
-
-[features]
-deny-warnings = []
diff --git a/src/tools/clippy/declare_clippy_lint/src/lib.rs b/src/tools/clippy/declare_clippy_lint/src/lib.rs
index 25b2fc9395c..ca070f6c250 100644
--- a/src/tools/clippy/declare_clippy_lint/src/lib.rs
+++ b/src/tools/clippy/declare_clippy_lint/src/lib.rs
@@ -1,5 +1,4 @@
 #![feature(let_chains)]
-#![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/lintcheck/Cargo.toml b/src/tools/clippy/lintcheck/Cargo.toml
index 350418eeeb8..b0e4e3e3e57 100644
--- a/src/tools/clippy/lintcheck/Cargo.toml
+++ b/src/tools/clippy/lintcheck/Cargo.toml
@@ -25,6 +25,3 @@ tar = "0.4"
 toml = "0.7.3"
 ureq = { version = "2.2", features = ["json"] }
 walkdir = "2.3"
-
-[features]
-deny-warnings = []
diff --git a/src/tools/clippy/lintcheck/src/config.rs b/src/tools/clippy/lintcheck/src/config.rs
index 6bec1753fc7..bd4fcc5e337 100644
--- a/src/tools/clippy/lintcheck/src/config.rs
+++ b/src/tools/clippy/lintcheck/src/config.rs
@@ -33,13 +33,13 @@ pub(crate) struct LintcheckConfig {
     /// Runs cargo clippy --fix and checks if all suggestions apply
     #[clap(long, conflicts_with("max_jobs"))]
     pub fix: bool,
-    /// Apply a filter to only collect specified lints, this also overrides `allow` attributes
+    /// Apply a filter to only collect specified lints
     #[clap(long = "filter", value_name = "clippy_lint_name", use_value_delimiter = true)]
     pub lint_filter: Vec<String>,
-    /// Set all lints to the "warn" lint level, even resitriction ones. Usually,
-    /// it's better to use `--filter` instead
+    /// Check all Clippy lints, by default only `clippy::all` and `clippy::pedantic` are checked.
+    /// Usually, it's better to use `--filter` instead
     #[clap(long, conflicts_with("lint_filter"))]
-    pub warn_all: bool,
+    pub all_lints: bool,
     /// Set the output format of the log file
     #[clap(long, short, default_value = "text")]
     pub format: OutputFormat,
diff --git a/src/tools/clippy/lintcheck/src/input.rs b/src/tools/clippy/lintcheck/src/input.rs
index 3b263674aa8..3383d50fa02 100644
--- a/src/tools/clippy/lintcheck/src/input.rs
+++ b/src/tools/clippy/lintcheck/src/input.rs
@@ -98,12 +98,12 @@ pub fn read_crates(toml_path: &Path) -> (Vec<CrateWithSource>, RecursiveOptions)
     let crate_list: SourceList =
         toml::from_str(&toml_content).unwrap_or_else(|e| panic!("Failed to parse {}: \n{e}", toml_path.display()));
     // parse the hashmap of the toml file into a list of crates
-    let tomlcrates: Vec<TomlCrate> = crate_list.crates.into_values().collect();
+    let toml_crates: Vec<TomlCrate> = crate_list.crates.into_values().collect();
 
     // flatten TomlCrates into CrateSources (one TomlCrates may represent several versions of a crate =>
-    // multiple Cratesources)
+    // multiple CrateSources)
     let mut crate_sources = Vec::new();
-    for tk in tomlcrates {
+    for tk in toml_crates {
         if let Some(ref path) = tk.path {
             crate_sources.push(CrateWithSource {
                 name: tk.name.clone(),
diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs
index 0dd62ded293..acb6eaa5278 100644
--- a/src/tools/clippy/lintcheck/src/main.rs
+++ b/src/tools/clippy/lintcheck/src/main.rs
@@ -119,7 +119,8 @@ impl Crate {
         cmd.arg(if config.fix { "fix" } else { "check" })
             .arg("--quiet")
             .current_dir(&self.path)
-            .env("CLIPPY_ARGS", clippy_args.join("__CLIPPY_HACKERY__"));
+            .env("CLIPPY_ARGS", clippy_args.join("__CLIPPY_HACKERY__"))
+            .env("CLIPPY_DISABLE_DOCS_LINKS", "1");
 
         if let Some(server) = server {
             // `cargo clippy` is a wrapper around `cargo check` that mainly sets `RUSTC_WORKSPACE_WRAPPER` to
@@ -284,29 +285,24 @@ fn lintcheck(config: LintcheckConfig) {
     let (crates, recursive_options) = read_crates(&config.sources_toml_path);
 
     let counter = AtomicUsize::new(1);
-    let mut lint_level_args: Vec<String> = vec![];
+    let mut lint_level_args: Vec<String> = vec!["--cap-lints=allow".into()];
     if config.lint_filter.is_empty() {
-        lint_level_args.push("--cap-lints=warn".to_string());
-
-        // Set allow-by-default to warn
-        if config.warn_all {
-            [
+        let groups = if config.all_lints {
+            &[
+                "clippy::all",
                 "clippy::cargo",
                 "clippy::nursery",
                 "clippy::pedantic",
                 "clippy::restriction",
-            ]
+            ][..]
+        } else {
+            &["clippy::all", "clippy::pedantic"]
+        };
+        groups
             .iter()
-            .map(|group| format!("--warn={group}"))
+            .map(|group| format!("--force-warn={group}"))
             .collect_into(&mut lint_level_args);
-        } else {
-            ["clippy::cargo", "clippy::pedantic"]
-                .iter()
-                .map(|group| format!("--warn={group}"))
-                .collect_into(&mut lint_level_args);
-        }
     } else {
-        lint_level_args.push("--cap-lints=allow".to_string());
         config
             .lint_filter
             .iter()
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index 69fb11a4824..5fbe4e544a9 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,4 +1,4 @@
 [toolchain]
-channel = "nightly-2024-07-25"
+channel = "nightly-2024-08-08"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
 profile = "minimal"
diff --git a/src/tools/clippy/rustc_tools_util/Cargo.toml b/src/tools/clippy/rustc_tools_util/Cargo.toml
index 877049ae7d0..37b592da132 100644
--- a/src/tools/clippy/rustc_tools_util/Cargo.toml
+++ b/src/tools/clippy/rustc_tools_util/Cargo.toml
@@ -10,6 +10,3 @@ categories = ["development-tools"]
 edition = "2018"
 
 [dependencies]
-
-[features]
-deny-warnings = []
diff --git a/src/tools/clippy/rustc_tools_util/src/lib.rs b/src/tools/clippy/rustc_tools_util/src/lib.rs
index 4c1d8c3733d..2cc38130472 100644
--- a/src/tools/clippy/rustc_tools_util/src/lib.rs
+++ b/src/tools/clippy/rustc_tools_util/src/lib.rs
@@ -1,4 +1,4 @@
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
+use std::str;
 
 /// This macro creates the version string during compilation from the
 /// current environment
@@ -101,49 +101,46 @@ impl std::fmt::Debug for VersionInfo {
 
 #[must_use]
 pub fn get_commit_hash() -> Option<String> {
-    std::process::Command::new("git")
-        .args(["rev-parse", "--short", "HEAD"])
+    let output = std::process::Command::new("git")
+        .args(["rev-parse", "HEAD"])
         .output()
-        .ok()
-        .and_then(|r| String::from_utf8(r.stdout).ok())
+        .ok()?;
+    let mut stdout = output.status.success().then_some(output.stdout)?;
+    stdout.truncate(10);
+    String::from_utf8(stdout).ok()
 }
 
 #[must_use]
 pub fn get_commit_date() -> Option<String> {
-    std::process::Command::new("git")
+    let output = std::process::Command::new("git")
         .args(["log", "-1", "--date=short", "--pretty=format:%cd"])
         .output()
-        .ok()
-        .and_then(|r| String::from_utf8(r.stdout).ok())
+        .ok()?;
+    let stdout = output.status.success().then_some(output.stdout)?;
+    String::from_utf8(stdout).ok()
 }
 
 #[must_use]
 pub fn get_channel() -> String {
-    match std::env::var("CFG_RELEASE_CHANNEL") {
-        Ok(channel) => channel,
-        Err(_) => {
-            // if that failed, try to ask rustc -V, do some parsing and find out
-            match std::process::Command::new("rustc")
-                .arg("-V")
-                .output()
-                .ok()
-                .and_then(|r| String::from_utf8(r.stdout).ok())
-            {
-                Some(rustc_output) => {
-                    if rustc_output.contains("beta") {
-                        String::from("beta")
-                    } else if rustc_output.contains("stable") {
-                        String::from("stable")
-                    } else {
-                        // default to nightly if we fail to parse
-                        String::from("nightly")
-                    }
-                },
-                // default to nightly
-                None => String::from("nightly"),
+    if let Ok(channel) = std::env::var("CFG_RELEASE_CHANNEL") {
+        return channel;
+    }
+
+    // if that failed, try to ask rustc -V, do some parsing and find out
+    if let Ok(output) = std::process::Command::new("rustc").arg("-V").output() {
+        if output.status.success() {
+            if let Ok(rustc_output) = str::from_utf8(&output.stdout) {
+                if rustc_output.contains("beta") {
+                    return String::from("beta");
+                } else if rustc_output.contains("stable") {
+                    return String::from("stable");
+                }
             }
-        },
+        }
     }
+
+    // default to nightly
+    String::from("nightly")
 }
 
 #[cfg(test)]
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index 9b1577f24b8..0ac3f35b446 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -2,8 +2,6 @@
 #![allow(rustc::untranslatable_diagnostic)]
 #![feature(rustc_private)]
 #![feature(let_chains)]
-#![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)]
 // warn on rustc internal lints
@@ -152,7 +150,6 @@ impl rustc_driver::Callbacks for ClippyCallbacks {
             let conf = clippy_config::Conf::read(sess, &conf_path);
             clippy_lints::register_lints(lint_store, conf);
             clippy_lints::register_pre_expansion_lints(lint_store, conf);
-            clippy_lints::register_renamed(lint_store);
         }));
 
         // FIXME: #4825; This is required, because Clippy lints that are based on MIR have to be
diff --git a/src/tools/clippy/src/main.rs b/src/tools/clippy/src/main.rs
index 30beaae34d2..c9853e53f3b 100644
--- a/src/tools/clippy/src/main.rs
+++ b/src/tools/clippy/src/main.rs
@@ -1,4 +1,6 @@
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
+// We need this feature as it changes `dylib` linking behavior and allows us to link to
+// `rustc_driver`.
+#![feature(rustc_private)]
 // 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/check-fmt.rs b/src/tools/clippy/tests/check-fmt.rs
index e106583de4a..cd3fed896c2 100644
--- a/src/tools/clippy/tests/check-fmt.rs
+++ b/src/tools/clippy/tests/check-fmt.rs
@@ -1,4 +1,3 @@
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
 use std::path::PathBuf;
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index 4e5120406b0..64253514fbe 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -1,4 +1,6 @@
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
+// We need this feature as it changes `dylib` linking behavior and allows us to link to
+// `rustc_driver`.
+#![feature(rustc_private)]
 #![warn(rust_2018_idioms, unused_lifetimes)]
 #![allow(unused_extern_crates)]
 
@@ -208,7 +210,8 @@ fn run_ui_toml() {
     ui_test::run_tests_generic(
         vec![config],
         ui_test::default_file_filter,
-        |config, path, _file_contents| {
+        |config, file_contents| {
+            let path = file_contents.span().file;
             config
                 .program
                 .envs
@@ -260,7 +263,7 @@ fn run_ui_cargo() {
             path.ends_with("Cargo.toml")
                 .then(|| ui_test::default_any_file_filter(path, config) && !ignored_32bit(path))
         },
-        |_config, _path, _file_contents| {},
+        |_config, _file_contents| {},
         status_emitter::Text::from(args.format),
     )
     .unwrap();
diff --git a/src/tools/clippy/tests/dogfood.rs b/src/tools/clippy/tests/dogfood.rs
index c8a761bf509..8d10d5e7161 100644
--- a/src/tools/clippy/tests/dogfood.rs
+++ b/src/tools/clippy/tests/dogfood.rs
@@ -3,7 +3,6 @@
 //!
 //! See [Eating your own dog food](https://en.wikipedia.org/wiki/Eating_your_own_dog_food) for context
 
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
 use itertools::Itertools;
diff --git a/src/tools/clippy/tests/integration.rs b/src/tools/clippy/tests/integration.rs
index 77b7bb6a7bf..13cf36823c5 100644
--- a/src/tools/clippy/tests/integration.rs
+++ b/src/tools/clippy/tests/integration.rs
@@ -8,7 +8,6 @@
 //! Clippy doesn't produce an ICE. Lint warnings are ignored by this test.
 
 #![cfg(feature = "integration")]
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
 use std::env;
diff --git a/src/tools/clippy/tests/lint_message_convention.rs b/src/tools/clippy/tests/lint_message_convention.rs
index 6ce7e44474d..7ed1f485c1c 100644
--- a/src/tools/clippy/tests/lint_message_convention.rs
+++ b/src/tools/clippy/tests/lint_message_convention.rs
@@ -1,4 +1,3 @@
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
 use std::ffi::OsStr;
diff --git a/src/tools/clippy/tests/missing-test-files.rs b/src/tools/clippy/tests/missing-test-files.rs
index 141c11ddb47..a8225d037e8 100644
--- a/src/tools/clippy/tests/missing-test-files.rs
+++ b/src/tools/clippy/tests/missing-test-files.rs
@@ -1,4 +1,3 @@
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![warn(rust_2018_idioms, unused_lifetimes)]
 #![allow(clippy::assertions_on_constants)]
 #![feature(path_file_prefix)]
diff --git a/src/tools/clippy/tests/ui-internal/default_deprecation_reason.rs b/src/tools/clippy/tests/ui-internal/default_deprecation_reason.rs
deleted file mode 100644
index c8961d5e1f0..00000000000
--- a/src/tools/clippy/tests/ui-internal/default_deprecation_reason.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-#![deny(clippy::internal)]
-#![feature(rustc_private)]
-
-#[macro_use]
-extern crate clippy_lints;
-use clippy_lints::deprecated_lints::ClippyDeprecatedLint;
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// TODO
-    #[clippy::version = "1.63.0"]
-    pub COOL_LINT_DEFAULT,
-    "default deprecation note"
-}
-
-declare_deprecated_lint! {
-    /// ### What it does
-    /// Nothing. This lint has been deprecated.
-    ///
-    /// ### Deprecation reason
-    /// This lint has been replaced by `cooler_lint`
-    #[clippy::version = "1.63.0"]
-    pub COOL_LINT,
-    "this lint has been replaced by `cooler_lint`"
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui-internal/default_deprecation_reason.stderr b/src/tools/clippy/tests/ui-internal/default_deprecation_reason.stderr
deleted file mode 100644
index 3b7c747c23f..00000000000
--- a/src/tools/clippy/tests/ui-internal/default_deprecation_reason.stderr
+++ /dev/null
@@ -1,22 +0,0 @@
-error: the lint `COOL_LINT_DEFAULT` has the default deprecation reason
-  --> tests/ui-internal/default_deprecation_reason.rs:8:1
-   |
-LL | / declare_deprecated_lint! {
-LL | |     /// ### What it does
-LL | |     /// Nothing. This lint has been deprecated.
-LL | |     ///
-...  |
-LL | |     "default deprecation note"
-LL | | }
-   | |_^
-   |
-note: the lint level is defined here
-  --> tests/ui-internal/default_deprecation_reason.rs:1:9
-   |
-LL | #![deny(clippy::internal)]
-   |         ^^^^^^^^^^^^^^^^
-   = note: `#[deny(clippy::default_deprecation_reason)]` implied by `#[deny(clippy::internal)]`
-   = note: this error originates in the macro `declare_deprecated_lint` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.rs b/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.rs
index 4375f324aca..858aab528a9 100644
--- a/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.rs
+++ b/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.rs
@@ -1,15 +1,19 @@
 //@aux-build:../../ui/auxiliary/proc_macros.rs
 #![rustfmt::skip]
 #![feature(custom_inner_attributes)]
-#![allow(unused)]
-#![allow(clippy::let_and_return)]
-#![allow(clippy::redundant_closure_call)]
-#![allow(clippy::no_effect)]
-#![allow(clippy::unnecessary_operation)]
-#![allow(clippy::never_loop)]
-#![allow(clippy::needless_if)]
 #![warn(clippy::excessive_nesting)]
-#![allow(clippy::collapsible_if, clippy::blocks_in_conditions)]
+#![allow(
+    unused,
+    clippy::let_and_return,
+    clippy::redundant_closure_call,
+    clippy::no_effect,
+    clippy::unnecessary_operation,
+    clippy::never_loop,
+    clippy::needless_if,
+    clippy::collapsible_if,
+    clippy::blocks_in_conditions,
+    clippy::single_match,
+)]
 
 #[macro_use]
 extern crate proc_macros;
diff --git a/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.stderr b/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.stderr
index dafcd442055..ccdaecdd481 100644
--- a/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.stderr
+++ b/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.stderr
@@ -1,5 +1,5 @@
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:21:25
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:25:25
    |
 LL |                 let w = { 3 };
    |                         ^^^^^
@@ -9,7 +9,7 @@ LL |                 let w = { 3 };
    = help: to override `-D warnings` add `#[allow(clippy::excessive_nesting)]`
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:67:17
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:71:17
    |
 LL | /                 impl C {
 LL | |                     pub fn c() {}
@@ -19,7 +19,7 @@ LL | |                 }
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:81:25
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:85:25
    |
 LL |                 let x = { 1 }; // not a warning, but cc is
    |                         ^^^^^
@@ -27,7 +27,7 @@ LL |                 let x = { 1 }; // not a warning, but cc is
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:98:17
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:102:17
    |
 LL | /                 pub mod e {
 LL | |                     pub mod f {}
@@ -37,7 +37,7 @@ LL | |                 } // not here
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:111:18
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:115:18
    |
 LL |     a_but_not({{{{{{{{0}}}}}}}});
    |                  ^^^^^^^^^^^
@@ -45,7 +45,7 @@ LL |     a_but_not({{{{{{{{0}}}}}}}});
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:112:12
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:116:12
    |
 LL |     a.a({{{{{{{{{0}}}}}}}}});
    |            ^^^^^^^^^^^^^
@@ -53,7 +53,7 @@ LL |     a.a({{{{{{{{{0}}}}}}}}});
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:113:12
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:117:12
    |
 LL |     (0, {{{{{{{1}}}}}}});
    |            ^^^^^^^^^
@@ -61,7 +61,7 @@ LL |     (0, {{{{{{{1}}}}}}});
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:118:25
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:122:25
    |
 LL |                   if true {
    |  _________________________^
@@ -74,7 +74,7 @@ LL | |                 }
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:130:29
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:134:29
    |
 LL |                   let z = (|| {
    |  _____________________________^
@@ -86,7 +86,7 @@ LL | |                 })();
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:149:13
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:153:13
    |
 LL |     y += {{{{{5}}}}};
    |             ^^^^^
@@ -94,7 +94,7 @@ LL |     y += {{{{{5}}}}};
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:150:20
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:154:20
    |
 LL |     let z = y + {{{{{{{{{5}}}}}}}}};
    |                    ^^^^^^^^^^^^^
@@ -102,7 +102,7 @@ LL |     let z = y + {{{{{{{{{5}}}}}}}}};
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:151:12
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:155:12
    |
 LL |     [0, {{{{{{{{{{0}}}}}}}}}}];
    |            ^^^^^^^^^^^^^^^
@@ -110,7 +110,7 @@ LL |     [0, {{{{{{{{{{0}}}}}}}}}}];
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:152:25
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:156:25
    |
 LL |     let mut xx = [0; {{{{{{{{100}}}}}}}}];
    |                         ^^^^^^^^^^^^^
@@ -118,7 +118,7 @@ LL |     let mut xx = [0; {{{{{{{{100}}}}}}}}];
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:153:11
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:157:11
    |
 LL |     xx[{{{{{{{{{{{{{{{{{{{{{{{{3}}}}}}}}}}}}}}}}}}}}}}}}];
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -126,7 +126,7 @@ LL |     xx[{{{{{{{{{{{{{{{{{{{{{{{{3}}}}}}}}}}}}}}}}}}}}}}}}];
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:154:13
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:158:13
    |
 LL |     &mut {{{{{{{{{{y}}}}}}}}}};
    |             ^^^^^^^^^^^^^^^
@@ -134,7 +134,7 @@ LL |     &mut {{{{{{{{{{y}}}}}}}}}};
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:156:17
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:160:17
    |
 LL |     for i in {{{{xx}}}} {{{{{{{{}}}}}}}}
    |                 ^^^^
@@ -142,7 +142,7 @@ LL |     for i in {{{{xx}}}} {{{{{{{{}}}}}}}}
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:156:28
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:160:28
    |
 LL |     for i in {{{{xx}}}} {{{{{{{{}}}}}}}}
    |                            ^^^^^^^^^^
@@ -150,7 +150,7 @@ LL |     for i in {{{{xx}}}} {{{{{{{{}}}}}}}}
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:158:28
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:162:28
    |
 LL |     while let Some(i) = {{{{{{Some(1)}}}}}} {{{{{{{}}}}}}}
    |                            ^^^^^^^^^^^^^
@@ -158,7 +158,7 @@ LL |     while let Some(i) = {{{{{{Some(1)}}}}}} {{{{{{{}}}}}}}
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:158:48
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:162:48
    |
 LL |     while let Some(i) = {{{{{{Some(1)}}}}}} {{{{{{{}}}}}}}
    |                                                ^^^^^^^^
@@ -166,7 +166,7 @@ LL |     while let Some(i) = {{{{{{Some(1)}}}}}} {{{{{{{}}}}}}}
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:160:14
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:164:14
    |
 LL |     while {{{{{{{{true}}}}}}}} {{{{{{{{{}}}}}}}}}
    |              ^^^^^^^^^^^^^^
@@ -174,7 +174,7 @@ LL |     while {{{{{{{{true}}}}}}}} {{{{{{{{{}}}}}}}}}
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:160:35
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:164:35
    |
 LL |     while {{{{{{{{true}}}}}}}} {{{{{{{{{}}}}}}}}}
    |                                   ^^^^^^^^^^^^
@@ -182,7 +182,7 @@ LL |     while {{{{{{{{true}}}}}}}} {{{{{{{{{}}}}}}}}}
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:162:23
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:166:23
    |
 LL |     let d = D { d: {{{{{{{{{{{{{{{{{{{{{{{3}}}}}}}}}}}}}}}}}}}}}}} };
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -190,7 +190,7 @@ LL |     let d = D { d: {{{{{{{{{{{{{{{{{{{{{{{3}}}}}}}}}}}}}}}}}}}}}}} };
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:164:8
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:168:8
    |
 LL |     {{{{1;}}}}..{{{{{{3}}}}}};
    |        ^^^^
@@ -198,7 +198,7 @@ LL |     {{{{1;}}}}..{{{{{{3}}}}}};
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:164:20
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:168:20
    |
 LL |     {{{{1;}}}}..{{{{{{3}}}}}};
    |                    ^^^^^^^
@@ -206,7 +206,7 @@ LL |     {{{{1;}}}}..{{{{{{3}}}}}};
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:165:8
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:169:8
    |
 LL |     {{{{1;}}}}..={{{{{{{{{{{{{{{{{{{{{{{{{{6}}}}}}}}}}}}}}}}}}}}}}}}}};
    |        ^^^^
@@ -214,7 +214,7 @@ LL |     {{{{1;}}}}..={{{{{{{{{{{{{{{{{{{{{{{{{{6}}}}}}}}}}}}}}}}}}}}}}}}}};
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:165:21
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:169:21
    |
 LL |     {{{{1;}}}}..={{{{{{{{{{{{{{{{{{{{{{{{{{6}}}}}}}}}}}}}}}}}}}}}}}}}};
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -222,7 +222,7 @@ LL |     {{{{1;}}}}..={{{{{{{{{{{{{{{{{{{{{{{{{{6}}}}}}}}}}}}}}}}}}}}}}}}}};
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:166:10
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:170:10
    |
 LL |     ..{{{{{{{5}}}}}}};
    |          ^^^^^^^^^
@@ -230,7 +230,7 @@ LL |     ..{{{{{{{5}}}}}}};
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:167:11
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:171:11
    |
 LL |     ..={{{{{3}}}}};
    |           ^^^^^
@@ -238,7 +238,7 @@ LL |     ..={{{{{3}}}}};
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:168:8
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:172:8
    |
 LL |     {{{{{1;}}}}}..;
    |        ^^^^^^
@@ -246,7 +246,7 @@ LL |     {{{{{1;}}}}}..;
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:170:20
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:174:20
    |
 LL |     loop { break {{{{1}}}} };
    |                    ^^^^^
@@ -254,7 +254,7 @@ LL |     loop { break {{{{1}}}} };
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:171:13
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:175:13
    |
 LL |     loop {{{{{{}}}}}}
    |             ^^^^^^
@@ -262,7 +262,7 @@ LL |     loop {{{{{{}}}}}}
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:173:14
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:177:14
    |
 LL |     match {{{{{{true}}}}}} {
    |              ^^^^^^^^^^
@@ -270,7 +270,7 @@ LL |     match {{{{{{true}}}}}} {
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:174:20
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:178:20
    |
 LL |         true => {{{{}}}},
    |                    ^^
@@ -278,7 +278,7 @@ LL |         true => {{{{}}}},
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:175:21
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:179:21
    |
 LL |         false => {{{{}}}},
    |                     ^^
@@ -286,7 +286,7 @@ LL |         false => {{{{}}}},
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:181:17
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:185:17
    |
 LL | /                 {
 LL | |                     println!("warning! :)");
@@ -296,7 +296,7 @@ LL | |                 }
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:190:28
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:194:28
    |
 LL |     async fn c() -> u32 {{{{{{{0}}}}}}}
    |                            ^^^^^^^^^
@@ -304,7 +304,7 @@ LL |     async fn c() -> u32 {{{{{{{0}}}}}}}
    = help: try refactoring your code to minimize nesting
 
 error: this block is too nested
-  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:196:8
+  --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:200:8
    |
 LL |     {{{{b().await}}}};
    |        ^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr
index 41d5afd3efe..320578bfabc 100644
--- a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr
+++ b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr
@@ -1,11 +1,15 @@
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:38:17
    |
 LL |         let _ = boxed_slice.get(1).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&boxed_slice[1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::get-unwrap` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::get_unwrap)]`
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &boxed_slice[1];
+   |                 ~~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:38:17
@@ -18,11 +22,16 @@ LL |         let _ = boxed_slice.get(1).unwrap();
    = note: `-D clippy::unwrap-used` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::unwrap_used)]`
 
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:39:17
    |
 LL |         let _ = some_slice.get(0).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_slice[0]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &some_slice[0];
+   |                 ~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:39:17
@@ -33,11 +42,16 @@ LL |         let _ = some_slice.get(0).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a Vec
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:40:17
    |
 LL |         let _ = some_vec.get(0).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vec[0]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &some_vec[0];
+   |                 ~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:40:17
@@ -48,11 +62,16 @@ LL |         let _ = some_vec.get(0).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a VecDeque
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:41:17
    |
 LL |         let _ = some_vecdeque.get(0).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vecdeque[0]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &some_vecdeque[0];
+   |                 ~~~~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:41:17
@@ -63,11 +82,16 @@ LL |         let _ = some_vecdeque.get(0).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a HashMap
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:42:17
    |
 LL |         let _ = some_hashmap.get(&1).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_hashmap[&1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &some_hashmap[&1];
+   |                 ~~~~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:42:17
@@ -78,11 +102,16 @@ LL |         let _ = some_hashmap.get(&1).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a BTreeMap
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:43:17
    |
 LL |         let _ = some_btreemap.get(&1).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_btreemap[&1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &some_btreemap[&1];
+   |                 ~~~~~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:43:17
@@ -93,11 +122,16 @@ LL |         let _ = some_btreemap.get(&1).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:47:21
    |
 LL |         let _: u8 = *boxed_slice.get(1).unwrap();
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[1]`
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _: u8 = boxed_slice[1];
+   |                     ~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:47:22
@@ -108,11 +142,16 @@ LL |         let _: u8 = *boxed_slice.get(1).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a slice
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:52:9
    |
 LL |         *boxed_slice.get_mut(0).unwrap() = 1;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[0]`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         boxed_slice[0] = 1;
+   |         ~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:52:10
@@ -123,11 +162,16 @@ LL |         *boxed_slice.get_mut(0).unwrap() = 1;
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a slice
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:53:9
    |
 LL |         *some_slice.get_mut(0).unwrap() = 1;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_slice[0]`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         some_slice[0] = 1;
+   |         ~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:53:10
@@ -138,11 +182,16 @@ LL |         *some_slice.get_mut(0).unwrap() = 1;
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a Vec
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:54:9
    |
 LL |         *some_vec.get_mut(0).unwrap() = 1;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0]`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         some_vec[0] = 1;
+   |         ~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:54:10
@@ -153,11 +202,16 @@ LL |         *some_vec.get_mut(0).unwrap() = 1;
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a VecDeque
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:55:9
    |
 LL |         *some_vecdeque.get_mut(0).unwrap() = 1;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vecdeque[0]`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         some_vecdeque[0] = 1;
+   |         ~~~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:55:10
@@ -168,11 +222,16 @@ LL |         *some_vecdeque.get_mut(0).unwrap() = 1;
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a Vec
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:67:17
    |
 LL |         let _ = some_vec.get(0..1).unwrap().to_vec();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = some_vec[0..1].to_vec();
+   |                 ~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:67:17
@@ -183,11 +242,16 @@ LL |         let _ = some_vec.get(0..1).unwrap().to_vec();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a Vec
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:68:17
    |
 LL |         let _ = some_vec.get_mut(0..1).unwrap().to_vec();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = some_vec[0..1].to_vec();
+   |                 ~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:68:17
@@ -198,17 +262,27 @@ LL |         let _ = some_vec.get_mut(0..1).unwrap().to_vec();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:75:13
    |
 LL |     let _ = boxed_slice.get(1).unwrap();
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&boxed_slice[1]`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |     let _ = &boxed_slice[1];
+   |             ~~~~~~~~~~~~~~~
 
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui-toml/unwrap_used/unwrap_used.rs:93:17
    |
 LL |         let _ = Box::new([0]).get(1).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&Box::new([0])[1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &Box::new([0])[1];
+   |                 ~~~~~~~~~~~~~~~~~
 
 error: aborting due to 28 previous errors
 
diff --git a/src/tools/clippy/tests/ui/assigning_clones.fixed b/src/tools/clippy/tests/ui/assigning_clones.fixed
index 60f6a385fc5..b376d55a402 100644
--- a/src/tools/clippy/tests/ui/assigning_clones.fixed
+++ b/src/tools/clippy/tests/ui/assigning_clones.fixed
@@ -3,6 +3,7 @@
 #![allow(clippy::ptr_arg)] // https://github.com/rust-lang/rust-clippy/issues/10612
 #![allow(clippy::needless_late_init)]
 #![allow(clippy::box_collection)]
+#![allow(clippy::boxed_local)]
 #![warn(clippy::assigning_clones)]
 
 use std::borrow::ToOwned;
@@ -182,6 +183,31 @@ impl Clone for AvoidRecursiveCloneFrom {
     }
 }
 
+// Deref handling
+fn clone_into_deref_method(mut a: DerefWrapper<HasCloneFrom>, b: HasCloneFrom) {
+    (*a).clone_from(&b);
+}
+
+fn clone_into_deref_with_clone_method(mut a: DerefWrapperWithClone<HasCloneFrom>, b: HasCloneFrom) {
+    (*a).clone_from(&b);
+}
+
+fn clone_into_box_method(mut a: Box<HasCloneFrom>, b: HasCloneFrom) {
+    (*a).clone_from(&b);
+}
+
+fn clone_into_self_deref_method(a: &mut DerefWrapperWithClone<HasCloneFrom>, b: DerefWrapperWithClone<HasCloneFrom>) {
+    a.clone_from(&b);
+}
+
+fn clone_into_deref_function(mut a: DerefWrapper<HasCloneFrom>, b: HasCloneFrom) {
+    Clone::clone_from(&mut *a, &b);
+}
+
+fn clone_into_box_function(mut a: Box<HasCloneFrom>, b: HasCloneFrom) {
+    Clone::clone_from(&mut *a, &b);
+}
+
 // ToOwned
 fn owned_method_mut_ref(mut_string: &mut String, ref_str: &str) {
     ref_str.clone_into(mut_string);
@@ -328,3 +354,45 @@ mod borrowck_conflicts {
         path = path.components().as_path().to_owned();
     }
 }
+
+struct DerefWrapper<T>(T);
+
+impl<T> Deref for DerefWrapper<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl<T> DerefMut for DerefWrapper<T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+struct DerefWrapperWithClone<T>(T);
+
+impl<T> Deref for DerefWrapperWithClone<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl<T> DerefMut for DerefWrapperWithClone<T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+impl<T: Clone> Clone for DerefWrapperWithClone<T> {
+    fn clone(&self) -> Self {
+        Self(self.0.clone())
+    }
+
+    fn clone_from(&mut self, source: &Self) {
+        *self = Self(source.0.clone());
+    }
+}
diff --git a/src/tools/clippy/tests/ui/assigning_clones.rs b/src/tools/clippy/tests/ui/assigning_clones.rs
index 6eb85be511a..11a5d4459c3 100644
--- a/src/tools/clippy/tests/ui/assigning_clones.rs
+++ b/src/tools/clippy/tests/ui/assigning_clones.rs
@@ -3,6 +3,7 @@
 #![allow(clippy::ptr_arg)] // https://github.com/rust-lang/rust-clippy/issues/10612
 #![allow(clippy::needless_late_init)]
 #![allow(clippy::box_collection)]
+#![allow(clippy::boxed_local)]
 #![warn(clippy::assigning_clones)]
 
 use std::borrow::ToOwned;
@@ -182,6 +183,31 @@ impl Clone for AvoidRecursiveCloneFrom {
     }
 }
 
+// Deref handling
+fn clone_into_deref_method(mut a: DerefWrapper<HasCloneFrom>, b: HasCloneFrom) {
+    *a = b.clone();
+}
+
+fn clone_into_deref_with_clone_method(mut a: DerefWrapperWithClone<HasCloneFrom>, b: HasCloneFrom) {
+    *a = b.clone();
+}
+
+fn clone_into_box_method(mut a: Box<HasCloneFrom>, b: HasCloneFrom) {
+    *a = b.clone();
+}
+
+fn clone_into_self_deref_method(a: &mut DerefWrapperWithClone<HasCloneFrom>, b: DerefWrapperWithClone<HasCloneFrom>) {
+    *a = b.clone();
+}
+
+fn clone_into_deref_function(mut a: DerefWrapper<HasCloneFrom>, b: HasCloneFrom) {
+    *a = Clone::clone(&b);
+}
+
+fn clone_into_box_function(mut a: Box<HasCloneFrom>, b: HasCloneFrom) {
+    *a = Clone::clone(&b);
+}
+
 // ToOwned
 fn owned_method_mut_ref(mut_string: &mut String, ref_str: &str) {
     *mut_string = ref_str.to_owned();
@@ -328,3 +354,45 @@ mod borrowck_conflicts {
         path = path.components().as_path().to_owned();
     }
 }
+
+struct DerefWrapper<T>(T);
+
+impl<T> Deref for DerefWrapper<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl<T> DerefMut for DerefWrapper<T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+struct DerefWrapperWithClone<T>(T);
+
+impl<T> Deref for DerefWrapperWithClone<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl<T> DerefMut for DerefWrapperWithClone<T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+impl<T: Clone> Clone for DerefWrapperWithClone<T> {
+    fn clone(&self) -> Self {
+        Self(self.0.clone())
+    }
+
+    fn clone_from(&mut self, source: &Self) {
+        *self = Self(source.0.clone());
+    }
+}
diff --git a/src/tools/clippy/tests/ui/assigning_clones.stderr b/src/tools/clippy/tests/ui/assigning_clones.stderr
index a68516376ab..19724a6d4ec 100644
--- a/src/tools/clippy/tests/ui/assigning_clones.stderr
+++ b/src/tools/clippy/tests/ui/assigning_clones.stderr
@@ -1,5 +1,5 @@
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:24:5
+  --> tests/ui/assigning_clones.rs:25:5
    |
 LL |     *mut_thing = value_thing.clone();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `mut_thing.clone_from(&value_thing)`
@@ -8,142 +8,178 @@ LL |     *mut_thing = value_thing.clone();
    = help: to override `-D warnings` add `#[allow(clippy::assigning_clones)]`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:28:5
+  --> tests/ui/assigning_clones.rs:29:5
    |
 LL |     *mut_thing = ref_thing.clone();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `mut_thing.clone_from(ref_thing)`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:32:5
+  --> tests/ui/assigning_clones.rs:33:5
    |
 LL |     mut_thing = ref_thing.clone();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `mut_thing.clone_from(ref_thing)`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:36:5
+  --> tests/ui/assigning_clones.rs:37:5
    |
 LL |     *mut_thing = Clone::clone(ref_thing);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(mut_thing, ref_thing)`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:40:5
+  --> tests/ui/assigning_clones.rs:41:5
    |
 LL |     mut_thing = Clone::clone(ref_thing);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(&mut mut_thing, ref_thing)`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:44:5
+  --> tests/ui/assigning_clones.rs:45:5
    |
 LL |     *mut_thing = Clone::clone(ref_thing);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(mut_thing, ref_thing)`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:48:5
+  --> tests/ui/assigning_clones.rs:49:5
    |
 LL |     *mut_thing = HasCloneFrom::clone(ref_thing);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(mut_thing, ref_thing)`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:52:5
+  --> tests/ui/assigning_clones.rs:53:5
    |
 LL |     *mut_thing = <HasCloneFrom as Clone>::clone(ref_thing);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(mut_thing, ref_thing)`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:57:5
+  --> tests/ui/assigning_clones.rs:58:5
    |
 LL |     *(mut_thing + &mut HasCloneFrom) = ref_thing.clone();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `(mut_thing + &mut HasCloneFrom).clone_from(ref_thing)`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:62:5
+  --> tests/ui/assigning_clones.rs:63:5
    |
 LL |     *mut_thing = (ref_thing + ref_thing).clone();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `mut_thing.clone_from(ref_thing + ref_thing)`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:67:5
+  --> tests/ui/assigning_clones.rs:68:5
    |
 LL |     s = format!("{} {}", "hello", "world").clone();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `s.clone_from(&format!("{} {}", "hello", "world"))`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:72:5
+  --> tests/ui/assigning_clones.rs:73:5
    |
 LL |     s = Clone::clone(&format!("{} {}", "hello", "world"));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(&mut s, &format!("{} {}", "hello", "world"))`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:78:9
+  --> tests/ui/assigning_clones.rs:79:9
    |
 LL |         a = b.clone();
    |         ^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:149:5
+  --> tests/ui/assigning_clones.rs:150:5
    |
 LL |     a = b.clone();
    |     ^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:156:5
+  --> tests/ui/assigning_clones.rs:157:5
    |
 LL |     a = b.clone();
    |     ^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:157:5
+  --> tests/ui/assigning_clones.rs:158:5
    |
 LL |     a = c.to_owned();
    |     ^^^^^^^^^^^^^^^^ help: use `clone_into()`: `c.clone_into(&mut a)`
 
+error: assigning the result of `Clone::clone()` may be inefficient
+  --> tests/ui/assigning_clones.rs:188:5
+   |
+LL |     *a = b.clone();
+   |     ^^^^^^^^^^^^^^ help: use `clone_from()`: `(*a).clone_from(&b)`
+
+error: assigning the result of `Clone::clone()` may be inefficient
+  --> tests/ui/assigning_clones.rs:192:5
+   |
+LL |     *a = b.clone();
+   |     ^^^^^^^^^^^^^^ help: use `clone_from()`: `(*a).clone_from(&b)`
+
+error: assigning the result of `Clone::clone()` may be inefficient
+  --> tests/ui/assigning_clones.rs:196:5
+   |
+LL |     *a = b.clone();
+   |     ^^^^^^^^^^^^^^ help: use `clone_from()`: `(*a).clone_from(&b)`
+
+error: assigning the result of `Clone::clone()` may be inefficient
+  --> tests/ui/assigning_clones.rs:200:5
+   |
+LL |     *a = b.clone();
+   |     ^^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)`
+
+error: assigning the result of `Clone::clone()` may be inefficient
+  --> tests/ui/assigning_clones.rs:204:5
+   |
+LL |     *a = Clone::clone(&b);
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(&mut *a, &b)`
+
+error: assigning the result of `Clone::clone()` may be inefficient
+  --> tests/ui/assigning_clones.rs:208:5
+   |
+LL |     *a = Clone::clone(&b);
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(&mut *a, &b)`
+
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:187:5
+  --> tests/ui/assigning_clones.rs:213:5
    |
 LL |     *mut_string = ref_str.to_owned();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(mut_string)`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:191:5
+  --> tests/ui/assigning_clones.rs:217:5
    |
 LL |     mut_string = ref_str.to_owned();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut mut_string)`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:212:5
+  --> tests/ui/assigning_clones.rs:238:5
    |
 LL |     **mut_box_string = ref_str.to_owned();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut (*mut_box_string))`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:216:5
+  --> tests/ui/assigning_clones.rs:242:5
    |
 LL |     **mut_box_string = ref_str.to_owned();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut (*mut_box_string))`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:220:5
+  --> tests/ui/assigning_clones.rs:246:5
    |
 LL |     *mut_thing = ToOwned::to_owned(ref_str);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ToOwned::clone_into(ref_str, mut_thing)`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:224:5
+  --> tests/ui/assigning_clones.rs:250:5
    |
 LL |     mut_thing = ToOwned::to_owned(ref_str);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ToOwned::clone_into(ref_str, &mut mut_thing)`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:229:5
+  --> tests/ui/assigning_clones.rs:255:5
    |
 LL |     s = format!("{} {}", "hello", "world").to_owned();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `format!("{} {}", "hello", "world").clone_into(&mut s)`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:234:5
+  --> tests/ui/assigning_clones.rs:260:5
    |
 LL |     s = ToOwned::to_owned(&format!("{} {}", "hello", "world"));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ToOwned::clone_into(&format!("{} {}", "hello", "world"), &mut s)`
 
-error: aborting due to 24 previous errors
+error: aborting due to 30 previous errors
 
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 b15857c325a..2adaecc96d6 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
@@ -9,7 +9,7 @@ note: the lint level is defined here
    |
 LL | #![deny(clippy::bind_instead_of_map)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: try
+help: use `map` instead
    |
 LL |     let _ = Some("42").map(|s| if s.len() < 42 { 0 } else { s.len() });
    |                        ~~~                       ~          ~~~~~~~
@@ -20,7 +20,7 @@ error: using `Result.and_then(|x| Ok(y))`, which is more succinctly expressed as
 LL |     let _ = Ok::<_, ()>("42").and_then(|s| if s.len() < 42 { Ok(0) } else { Ok(s.len()) });
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: try
+help: use `map` instead
    |
 LL |     let _ = Ok::<_, ()>("42").map(|s| if s.len() < 42 { 0 } else { s.len() });
    |                               ~~~                       ~          ~~~~~~~
@@ -31,7 +31,7 @@ error: using `Result.or_else(|x| Err(y))`, which is more succinctly expressed as
 LL |     let _ = Err::<(), _>("42").or_else(|s| if s.len() < 42 { Err(s.len() + 20) } else { Err(s.len()) });
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: try
+help: use `map_err` instead
    |
 LL |     let _ = Err::<(), _>("42").map_err(|s| if s.len() < 42 { s.len() + 20 } else { s.len() });
    |                                ~~~~~~~                       ~~~~~~~~~~~~          ~~~~~~~
@@ -48,7 +48,7 @@ LL | |         }
 LL | |     });
    | |______^
    |
-help: try
+help: use `map` instead
    |
 LL ~     Some("42").map(|s| {
 LL |         if {
@@ -82,7 +82,7 @@ error: using `Option.and_then(|x| Some(y))`, which is more succinctly expressed
 LL |     let _ = Some("").and_then(|s| if s.len() == 20 { Some(m!()) } else { Some(Some(20)) });
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: try
+help: use `map` instead
    |
 LL |     let _ = Some("").map(|s| if s.len() == 20 { m!() } else { Some(20) });
    |                      ~~~                        ~~~~          ~~~~~~~~
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs
index 0ea93dd8462..452d1b19813 100644
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs
+++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs
@@ -10,7 +10,7 @@ use std::sync::Once;
 
 const ATOMIC: AtomicUsize = AtomicUsize::new(5);
 const CELL: Cell<usize> = Cell::new(6);
-const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec<AtomicUsize>, u8) = ([ATOMIC], Vec::new(), 7);
+const ATOMIC_TUPLE: ([AtomicUsize; 1], Option<Box<AtomicUsize>>, u8) = ([ATOMIC], None, 7);
 const INTEGER: u8 = 8;
 const STRING: String = String::new();
 const STR: &str = "012345";
@@ -74,7 +74,6 @@ fn main() {
     let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR: interior mutability
     let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR: interior mutability
     let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR: interior mutability
-    let _ = &*ATOMIC_TUPLE.1;
     let _ = &ATOMIC_TUPLE.2;
     let _ = (&&&&ATOMIC_TUPLE).0;
     let _ = (&&&&ATOMIC_TUPLE).2;
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr
index 33c774667f9..9a9028c8649 100644
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr
+++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr
@@ -92,7 +92,7 @@ LL |     let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst);
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:82:13
+  --> tests/ui/borrow_interior_mutable_const/others.rs:81:13
    |
 LL |     let _ = ATOMIC_TUPLE.0[0];
    |             ^^^^^^^^^^^^
@@ -100,7 +100,7 @@ LL |     let _ = ATOMIC_TUPLE.0[0];
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:87:5
+  --> tests/ui/borrow_interior_mutable_const/others.rs:86:5
    |
 LL |     CELL.set(2);
    |     ^^^^
@@ -108,7 +108,7 @@ LL |     CELL.set(2);
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:88:16
+  --> tests/ui/borrow_interior_mutable_const/others.rs:87:16
    |
 LL |     assert_eq!(CELL.get(), 6);
    |                ^^^^
diff --git a/src/tools/clippy/tests/ui/crashes/ice-3717.stderr b/src/tools/clippy/tests/ui/crashes/ice-3717.stderr
index 01627ff5b94..4b4618ee1bb 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-3717.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-3717.stderr
@@ -9,14 +9,13 @@ note: the lint level is defined here
    |
 LL | #![deny(clippy::implicit_hasher)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^
-help: consider adding a type parameter
+help: add a type parameter for `BuildHasher`
    |
-LL | pub fn ice_3717<S: ::std::hash::BuildHasher + Default>(_: &HashSet<usize, S>) {
-   |                +++++++++++++++++++++++++++++++++++++++     ~~~~~~~~~~~~~~~~~
-help: ...and use generic constructor
+LL ~ pub fn ice_3717<S: ::std::hash::BuildHasher + Default>(_: &HashSet<usize, S>) {
+LL |
+LL |     let _ = [0u8; 0];
+LL ~     let _: HashSet<usize> = HashSet::default();
    |
-LL |     let _: HashSet<usize> = HashSet::default();
-   |                             ~~~~~~~~~~~~~~~~~~
 
 error: aborting due to 1 previous error
 
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6254.rs b/src/tools/clippy/tests/ui/crashes/ice-6254.rs
index 8af60890390..aaca32ab2d9 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-6254.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-6254.rs
@@ -2,7 +2,8 @@
 // panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())',
 // compiler/rustc_mir_build/src/thir/pattern/_match.rs:2030:5
 
-#[allow(clippy::derive_partial_eq_without_eq)]
+#![allow(clippy::derive_partial_eq_without_eq, clippy::single_match)]
+
 #[derive(PartialEq)]
 struct Foo(i32);
 const FOO_REF_REF: &&Foo = &&Foo(42);
diff --git a/src/tools/clippy/tests/ui/create_dir.stderr b/src/tools/clippy/tests/ui/create_dir.stderr
index 9c6e640ca78..ab51705bb55 100644
--- a/src/tools/clippy/tests/ui/create_dir.stderr
+++ b/src/tools/clippy/tests/ui/create_dir.stderr
@@ -2,16 +2,25 @@ error: calling `std::fs::create_dir` where there may be a better way
   --> tests/ui/create_dir.rs:10:5
    |
 LL |     std::fs::create_dir("foo");
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `std::fs::create_dir_all` instead: `create_dir_all("foo")`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::create-dir` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::create_dir)]`
+help: consider calling `std::fs::create_dir_all` instead
+   |
+LL |     create_dir_all("foo");
+   |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: calling `std::fs::create_dir` where there may be a better way
   --> tests/ui/create_dir.rs:11:5
    |
 LL |     std::fs::create_dir("bar").unwrap();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `std::fs::create_dir_all` instead: `create_dir_all("bar")`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider calling `std::fs::create_dir_all` instead
+   |
+LL |     create_dir_all("bar").unwrap();
+   |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: aborting due to 2 previous errors
 
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 7d3c3f7c918..b3d74b9ff61 100644
--- a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr
+++ b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr
@@ -81,7 +81,7 @@ error: the `dbg!` macro is intended as a debugging tool
   --> tests/ui/dbg_macro/dbg_macro.rs:48:5
    |
 LL |     dbg!();
-   |     ^^^^^^^
+   |     ^^^^^^
    |
 help: remove the invocation before committing it to a version control system
    |
@@ -136,7 +136,7 @@ error: the `dbg!` macro is intended as a debugging tool
   --> tests/ui/dbg_macro/dbg_macro.rs:43:13
    |
 LL |             dbg!();
-   |             ^^^^^^^
+   |             ^^^^^^
 ...
 LL |     expand_to_dbg!();
    |     ---------------- in this macro invocation
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 16e51f4742e..b8e91906b93 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
@@ -2,7 +2,7 @@ error: the `dbg!` macro is intended as a debugging tool
   --> tests/ui/dbg_macro/auxiliary/submodule.rs:2:5
    |
 LL |     dbg!();
-   |     ^^^^^^^
+   |     ^^^^^^
    |
    = note: `-D clippy::dbg-macro` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::dbg_macro)]`
diff --git a/src/tools/clippy/tests/ui/deprecated.rs b/src/tools/clippy/tests/ui/deprecated.rs
index d3c34fb3716..5617db90a47 100644
--- a/src/tools/clippy/tests/ui/deprecated.rs
+++ b/src/tools/clippy/tests/ui/deprecated.rs
@@ -2,23 +2,18 @@
 // Use that command to update this file and do not edit by hand.
 // Manual edits will be overwritten.
 
-#![warn(clippy::should_assert_eq)]
-#![warn(clippy::extend_from_slice)]
-#![warn(clippy::range_step_by_zero)]
-#![warn(clippy::unstable_as_slice)]
-#![warn(clippy::unstable_as_mut_slice)]
-#![warn(clippy::misaligned_transmute)]
-#![warn(clippy::assign_ops)]
-#![warn(clippy::if_let_redundant_pattern_matching)]
-#![warn(clippy::unsafe_vector_initialization)]
-#![warn(clippy::unused_collect)]
-#![warn(clippy::replace_consts)]
-#![warn(clippy::regex_macro)]
-#![warn(clippy::find_map)]
-#![warn(clippy::filter_map)]
-#![warn(clippy::pub_enum_variant_names)]
-#![warn(clippy::wrong_pub_self_convention)]
-#![warn(clippy::maybe_misused_cfg)]
-#![warn(clippy::mismatched_target_os)]
+#![warn(clippy::should_assert_eq)] //~ ERROR: lint `clippy::should_assert_eq`
+#![warn(clippy::extend_from_slice)] //~ ERROR: lint `clippy::extend_from_slice`
+#![warn(clippy::range_step_by_zero)] //~ ERROR: lint `clippy::range_step_by_zero`
+#![warn(clippy::unstable_as_slice)] //~ ERROR: lint `clippy::unstable_as_slice`
+#![warn(clippy::unstable_as_mut_slice)] //~ ERROR: lint `clippy::unstable_as_mut_slice`
+#![warn(clippy::misaligned_transmute)] //~ ERROR: lint `clippy::misaligned_transmute`
+#![warn(clippy::assign_ops)] //~ ERROR: lint `clippy::assign_ops`
+#![warn(clippy::unsafe_vector_initialization)] //~ ERROR: lint `clippy::unsafe_vector_initialization`
+#![warn(clippy::unused_collect)] //~ ERROR: lint `clippy::unused_collect`
+#![warn(clippy::replace_consts)] //~ ERROR: lint `clippy::replace_consts`
+#![warn(clippy::regex_macro)] //~ ERROR: lint `clippy::regex_macro`
+#![warn(clippy::pub_enum_variant_names)] //~ ERROR: lint `clippy::pub_enum_variant_names`
+#![warn(clippy::wrong_pub_self_convention)] //~ ERROR: lint `clippy::wrong_pub_self_convention`
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/deprecated.stderr b/src/tools/clippy/tests/ui/deprecated.stderr
index 49b90c70c06..b3e1646c804 100644
--- a/src/tools/clippy/tests/ui/deprecated.stderr
+++ b/src/tools/clippy/tests/ui/deprecated.stderr
@@ -1,4 +1,4 @@
-error: lint `clippy::should_assert_eq` has been removed: `assert!()` will be more flexible with RFC 2011
+error: lint `clippy::should_assert_eq` has been removed: `assert!(a == b)` can now print the values the same way `assert_eq!(a, b) can
   --> tests/ui/deprecated.rs:5:9
    |
 LL | #![warn(clippy::should_assert_eq)]
@@ -7,107 +7,77 @@ LL | #![warn(clippy::should_assert_eq)]
    = note: `-D renamed-and-removed-lints` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]`
 
-error: lint `clippy::extend_from_slice` has been removed: `.extend_from_slice(_)` is a faster way to extend a Vec by a slice
+error: lint `clippy::extend_from_slice` has been removed: `Vec::extend_from_slice` is no longer faster than `Vec::extend` due to specialization
   --> tests/ui/deprecated.rs:6:9
    |
 LL | #![warn(clippy::extend_from_slice)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::range_step_by_zero` has been removed: `iterator.step_by(0)` panics nowadays
+error: lint `clippy::range_step_by_zero` has been removed: `Iterator::step_by(0)` now panics and is no longer an infinite iterator
   --> tests/ui/deprecated.rs:7:9
    |
 LL | #![warn(clippy::range_step_by_zero)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7
+error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` is now stable
   --> tests/ui/deprecated.rs:8:9
    |
 LL | #![warn(clippy::unstable_as_slice)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` has been stabilized in 1.7
+error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` is now stable
   --> tests/ui/deprecated.rs:9:9
    |
 LL | #![warn(clippy::unstable_as_mut_slice)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::misaligned_transmute` has been removed: this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr
+error: lint `clippy::misaligned_transmute` has been removed: split into `clippy::cast_ptr_alignment` and `clippy::transmute_ptr_to_ptr`
   --> tests/ui/deprecated.rs:10:9
    |
 LL | #![warn(clippy::misaligned_transmute)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::assign_ops` has been removed: using compound assignment operators (e.g., `+=`) is harmless
+error: lint `clippy::assign_ops` has been removed: compound operators are harmless and linting on them is not in scope for clippy
   --> tests/ui/deprecated.rs:11:9
    |
 LL | #![warn(clippy::assign_ops)]
    |         ^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::if_let_redundant_pattern_matching` has been removed: this lint has been changed to redundant_pattern_matching
+error: lint `clippy::unsafe_vector_initialization` has been removed: the suggested alternative could be substantially slower
   --> tests/ui/deprecated.rs:12:9
    |
-LL | #![warn(clippy::if_let_redundant_pattern_matching)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: lint `clippy::unsafe_vector_initialization` has been removed: the replacement suggested by this lint had substantially different behavior
-  --> tests/ui/deprecated.rs:13:9
-   |
 LL | #![warn(clippy::unsafe_vector_initialization)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::unused_collect` has been removed: `collect` has been marked as #[must_use] in rustc and that covers all cases of this lint
-  --> tests/ui/deprecated.rs:14:9
+error: lint `clippy::unused_collect` has been removed: `Iterator::collect` is now marked as `#[must_use]`
+  --> tests/ui/deprecated.rs:13:9
    |
 LL | #![warn(clippy::unused_collect)]
    |         ^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::replace_consts` has been removed: associated-constants `MIN`/`MAX` of integers are preferred to `{min,max}_value()` and module constants
-  --> tests/ui/deprecated.rs:15:9
+error: lint `clippy::replace_consts` has been removed: `min_value` and `max_value` are now deprecated
+  --> tests/ui/deprecated.rs:14:9
    |
 LL | #![warn(clippy::replace_consts)]
    |         ^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::regex_macro` has been removed: the regex! macro has been removed from the regex crate in 2018
-  --> tests/ui/deprecated.rs:16:9
+error: lint `clippy::regex_macro` has been removed: the `regex!` macro was removed from the regex crate in 2018
+  --> tests/ui/deprecated.rs:15:9
    |
 LL | #![warn(clippy::regex_macro)]
    |         ^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::find_map` has been removed: this lint has been replaced by `manual_find_map`, a more specific lint
-  --> tests/ui/deprecated.rs:17:9
-   |
-LL | #![warn(clippy::find_map)]
-   |         ^^^^^^^^^^^^^^^^
-
-error: lint `clippy::filter_map` has been removed: this lint has been replaced by `manual_filter_map`, a more specific lint
-  --> tests/ui/deprecated.rs:18:9
-   |
-LL | #![warn(clippy::filter_map)]
-   |         ^^^^^^^^^^^^^^^^^^
-
-error: lint `clippy::pub_enum_variant_names` has been removed: set the `avoid-breaking-exported-api` config option to `false` to enable the `enum_variant_names` lint for public items
-  --> tests/ui/deprecated.rs:19:9
+error: lint `clippy::pub_enum_variant_names` has been removed: `clippy::enum_variant_names` now covers this case via the `avoid-breaking-exported-api` config
+  --> tests/ui/deprecated.rs:16:9
    |
 LL | #![warn(clippy::pub_enum_variant_names)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::wrong_pub_self_convention` has been removed: set the `avoid-breaking-exported-api` config option to `false` to enable the `wrong_self_convention` lint for public items
-  --> tests/ui/deprecated.rs:20:9
+error: lint `clippy::wrong_pub_self_convention` has been removed: `clippy::wrong_self_convention` now covers this case via the `avoid-breaking-exported-api` config
+  --> tests/ui/deprecated.rs:17:9
    |
 LL | #![warn(clippy::wrong_pub_self_convention)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::maybe_misused_cfg` has been removed: this lint has been replaced by `unexpected_cfgs`
-  --> tests/ui/deprecated.rs:21:9
-   |
-LL | #![warn(clippy::maybe_misused_cfg)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: lint `clippy::mismatched_target_os` has been removed: this lint has been replaced by `unexpected_cfgs`
-  --> tests/ui/deprecated.rs:22:9
-   |
-LL | #![warn(clippy::mismatched_target_os)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 18 previous errors
+error: aborting due to 13 previous errors
 
diff --git a/src/tools/clippy/tests/ui/deprecated_old.rs b/src/tools/clippy/tests/ui/deprecated_old.rs
deleted file mode 100644
index 356ad5f060b..00000000000
--- a/src/tools/clippy/tests/ui/deprecated_old.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-#[warn(unstable_as_slice)]
-//~^ ERROR: lint `unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized
-//~| NOTE: `-D renamed-and-removed-lints` implied by `-D warnings`
-#[warn(unstable_as_mut_slice)]
-//~^ ERROR: lint `unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` has been st
-#[warn(misaligned_transmute)]
-//~^ ERROR: lint `misaligned_transmute` has been removed: this lint has been split into ca
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/deprecated_old.stderr b/src/tools/clippy/tests/ui/deprecated_old.stderr
deleted file mode 100644
index 685bca64df5..00000000000
--- a/src/tools/clippy/tests/ui/deprecated_old.stderr
+++ /dev/null
@@ -1,23 +0,0 @@
-error: lint `unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7
-  --> tests/ui/deprecated_old.rs:1:8
-   |
-LL | #[warn(unstable_as_slice)]
-   |        ^^^^^^^^^^^^^^^^^
-   |
-   = note: `-D renamed-and-removed-lints` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]`
-
-error: lint `unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` has been stabilized in 1.7
-  --> tests/ui/deprecated_old.rs:4:8
-   |
-LL | #[warn(unstable_as_mut_slice)]
-   |        ^^^^^^^^^^^^^^^^^^^^^
-
-error: lint `misaligned_transmute` has been removed: this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr
-  --> tests/ui/deprecated_old.rs:6:8
-   |
-LL | #[warn(misaligned_transmute)]
-   |        ^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 3 previous errors
-
diff --git a/src/tools/clippy/tests/ui/deref_by_slicing.fixed b/src/tools/clippy/tests/ui/deref_by_slicing.fixed
index a3c2e845666..87b33b1f881 100644
--- a/src/tools/clippy/tests/ui/deref_by_slicing.fixed
+++ b/src/tools/clippy/tests/ui/deref_by_slicing.fixed
@@ -25,4 +25,8 @@ fn main() {
 
     let bytes: &[u8] = &[];
     let _ = (&*bytes).read_to_end(&mut vec![]).unwrap(); // Err, re-borrows slice
+
+    // issue 12751
+    let a = &mut [1, 2, 3][..];
+    let _ = &*a;
 }
diff --git a/src/tools/clippy/tests/ui/deref_by_slicing.rs b/src/tools/clippy/tests/ui/deref_by_slicing.rs
index 5b4a73712ee..8d8882a1781 100644
--- a/src/tools/clippy/tests/ui/deref_by_slicing.rs
+++ b/src/tools/clippy/tests/ui/deref_by_slicing.rs
@@ -25,4 +25,8 @@ fn main() {
 
     let bytes: &[u8] = &[];
     let _ = (&bytes[..]).read_to_end(&mut vec![]).unwrap(); // Err, re-borrows slice
+
+    // issue 12751
+    let a = &mut [1, 2, 3][..];
+    let _ = &a[..];
 }
diff --git a/src/tools/clippy/tests/ui/deref_by_slicing.stderr b/src/tools/clippy/tests/ui/deref_by_slicing.stderr
index 17b00610899..ceb9ab6db73 100644
--- a/src/tools/clippy/tests/ui/deref_by_slicing.stderr
+++ b/src/tools/clippy/tests/ui/deref_by_slicing.stderr
@@ -55,5 +55,11 @@ error: slicing when dereferencing would work
 LL |     let _ = (&bytes[..]).read_to_end(&mut vec![]).unwrap(); // Err, re-borrows slice
    |             ^^^^^^^^^^^^ help: reborrow the original value instead: `(&*bytes)`
 
-error: aborting due to 9 previous errors
+error: slicing when dereferencing would work
+  --> tests/ui/deref_by_slicing.rs:31:13
+   |
+LL |     let _ = &a[..];
+   |             ^^^^^^ help: reborrow the original value instead: `&*a`
+
+error: aborting due to 10 previous errors
 
diff --git a/src/tools/clippy/tests/ui/doc/footnote_issue_13183.rs b/src/tools/clippy/tests/ui/doc/footnote_issue_13183.rs
new file mode 100644
index 00000000000..a18b4c3ac53
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc/footnote_issue_13183.rs
@@ -0,0 +1,10 @@
+// This is a regression test for <https://github.com/rust-lang/rust-clippy/issues/13183>.
+// It should not warn on missing backticks on footnote references.
+
+#![warn(clippy::doc_markdown)]
+// Should not warn!
+//! Here's a footnote[^example_footnote_identifier]
+//!
+//! [^example_footnote_identifier]: This is merely an example.
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/empty_drop.stderr b/src/tools/clippy/tests/ui/empty_drop.stderr
index 4223ddaf3fb..d4d020fec30 100644
--- a/src/tools/clippy/tests/ui/empty_drop.stderr
+++ b/src/tools/clippy/tests/ui/empty_drop.stderr
@@ -4,10 +4,11 @@ error: empty drop implementation
 LL | / impl Drop for Foo {
 LL | |     fn drop(&mut self) {}
 LL | | }
-   | |_^ help: try removing this impl
+   | |_^
    |
    = note: `-D clippy::empty-drop` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::empty_drop)]`
+   = help: try removing this impl
 
 error: empty drop implementation
   --> tests/ui/empty_drop.rs:23:1
@@ -17,7 +18,9 @@ LL | |     fn drop(&mut self) {
 LL | |         {}
 LL | |     }
 LL | | }
-   | |_^ help: try removing this impl
+   | |_^
+   |
+   = help: try removing this impl
 
 error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui/eta.fixed b/src/tools/clippy/tests/ui/eta.fixed
index 7126f279945..ca422ee29c1 100644
--- a/src/tools/clippy/tests/ui/eta.fixed
+++ b/src/tools/clippy/tests/ui/eta.fixed
@@ -2,6 +2,7 @@
 #![allow(unused)]
 #![allow(
     clippy::needless_borrow,
+    clippy::needless_option_as_deref,
     clippy::needless_pass_by_value,
     clippy::no_effect,
     clippy::option_map_unit_fn,
@@ -482,3 +483,19 @@ mod issue_12853 {
         x();
     }
 }
+
+mod issue_13073 {
+    fn get_default() -> Option<&'static str> {
+        Some("foo")
+    }
+
+    pub fn foo() {
+        // shouldn't lint
+        let bind: Option<String> = None;
+        let _field = bind.as_deref().or_else(|| get_default()).unwrap();
+        let bind: Option<&'static str> = None;
+        let _field = bind.as_deref().or_else(|| get_default()).unwrap();
+        // should lint
+        let _field = bind.or_else(get_default).unwrap();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/eta.rs b/src/tools/clippy/tests/ui/eta.rs
index 0787abf5f3e..c0db91c03ef 100644
--- a/src/tools/clippy/tests/ui/eta.rs
+++ b/src/tools/clippy/tests/ui/eta.rs
@@ -2,6 +2,7 @@
 #![allow(unused)]
 #![allow(
     clippy::needless_borrow,
+    clippy::needless_option_as_deref,
     clippy::needless_pass_by_value,
     clippy::no_effect,
     clippy::option_map_unit_fn,
@@ -482,3 +483,19 @@ mod issue_12853 {
         x();
     }
 }
+
+mod issue_13073 {
+    fn get_default() -> Option<&'static str> {
+        Some("foo")
+    }
+
+    pub fn foo() {
+        // shouldn't lint
+        let bind: Option<String> = None;
+        let _field = bind.as_deref().or_else(|| get_default()).unwrap();
+        let bind: Option<&'static str> = None;
+        let _field = bind.as_deref().or_else(|| get_default()).unwrap();
+        // should lint
+        let _field = bind.or_else(|| get_default()).unwrap();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/eta.stderr b/src/tools/clippy/tests/ui/eta.stderr
index c757601042f..5540261fc57 100644
--- a/src/tools/clippy/tests/ui/eta.stderr
+++ b/src/tools/clippy/tests/ui/eta.stderr
@@ -1,5 +1,5 @@
 error: redundant closure
-  --> tests/ui/eta.rs:29:27
+  --> tests/ui/eta.rs:30:27
    |
 LL |     let a = Some(1u8).map(|a| foo(a));
    |                           ^^^^^^^^^^ help: replace the closure with the function itself: `foo`
@@ -8,31 +8,31 @@ LL |     let a = Some(1u8).map(|a| foo(a));
    = help: to override `-D warnings` add `#[allow(clippy::redundant_closure)]`
 
 error: redundant closure
-  --> tests/ui/eta.rs:33:40
+  --> tests/ui/eta.rs:34:40
    |
 LL |     let _: Option<Vec<u8>> = true.then(|| vec![]); // special case vec!
    |                                        ^^^^^^^^^ help: replace the closure with `Vec::new`: `std::vec::Vec::new`
 
 error: redundant closure
-  --> tests/ui/eta.rs:34:35
+  --> tests/ui/eta.rs:35:35
    |
 LL |     let d = Some(1u8).map(|a| foo((|b| foo2(b))(a))); //is adjusted?
    |                                   ^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo2`
 
 error: redundant closure
-  --> tests/ui/eta.rs:35:26
+  --> tests/ui/eta.rs:36:26
    |
 LL |     all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted
    |                          ^^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `below`
 
 error: redundant closure
-  --> tests/ui/eta.rs:42:27
+  --> tests/ui/eta.rs:43:27
    |
 LL |     let e = Some(1u8).map(|a| generic(a));
    |                           ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `generic`
 
 error: redundant closure
-  --> tests/ui/eta.rs:94:51
+  --> tests/ui/eta.rs:95:51
    |
 LL |     let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo());
    |                                                   ^^^^^^^^^^^ help: replace the closure with the method itself: `TestStruct::foo`
@@ -41,166 +41,172 @@ LL |     let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo());
    = help: to override `-D warnings` add `#[allow(clippy::redundant_closure_for_method_calls)]`
 
 error: redundant closure
-  --> tests/ui/eta.rs:95:51
+  --> tests/ui/eta.rs:96:51
    |
 LL |     let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo());
    |                                                   ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `TestTrait::trait_foo`
 
 error: redundant closure
-  --> tests/ui/eta.rs:97:42
+  --> tests/ui/eta.rs:98:42
    |
 LL |     let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear());
    |                                          ^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::vec::Vec::clear`
 
 error: redundant closure
-  --> tests/ui/eta.rs:101:29
+  --> tests/ui/eta.rs:102:29
    |
 LL |     let e = Some("str").map(|s| s.to_string());
    |                             ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::string::ToString::to_string`
 
 error: redundant closure
-  --> tests/ui/eta.rs:102:27
+  --> tests/ui/eta.rs:103:27
    |
 LL |     let e = Some('a').map(|s| s.to_uppercase());
    |                           ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_uppercase`
 
 error: redundant closure
-  --> tests/ui/eta.rs:104:65
+  --> tests/ui/eta.rs:105:65
    |
 LL |     let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect();
    |                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_ascii_uppercase`
 
 error: redundant closure
-  --> tests/ui/eta.rs:167:22
+  --> tests/ui/eta.rs:168:22
    |
 LL |     requires_fn_once(|| x());
    |                      ^^^^^^ help: replace the closure with the function itself: `x`
 
 error: redundant closure
-  --> tests/ui/eta.rs:174:27
+  --> tests/ui/eta.rs:175:27
    |
 LL |     let a = Some(1u8).map(|a| foo_ptr(a));
    |                           ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo_ptr`
 
 error: redundant closure
-  --> tests/ui/eta.rs:179:27
+  --> tests/ui/eta.rs:180:27
    |
 LL |     let a = Some(1u8).map(|a| closure(a));
    |                           ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `closure`
 
 error: redundant closure
-  --> tests/ui/eta.rs:211:28
+  --> tests/ui/eta.rs:212:28
    |
 LL |     x.into_iter().for_each(|x| add_to_res(x));
    |                            ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res`
 
 error: redundant closure
-  --> tests/ui/eta.rs:212:28
+  --> tests/ui/eta.rs:213:28
    |
 LL |     y.into_iter().for_each(|x| add_to_res(x));
    |                            ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res`
 
 error: redundant closure
-  --> tests/ui/eta.rs:213:28
+  --> tests/ui/eta.rs:214:28
    |
 LL |     z.into_iter().for_each(|x| add_to_res(x));
    |                            ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `add_to_res`
 
 error: redundant closure
-  --> tests/ui/eta.rs:220:21
+  --> tests/ui/eta.rs:221:21
    |
 LL |         Some(1).map(|n| closure(n));
    |                     ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut closure`
 
 error: redundant closure
-  --> tests/ui/eta.rs:224:21
+  --> tests/ui/eta.rs:225:21
    |
 LL |         Some(1).map(|n| in_loop(n));
    |                     ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `in_loop`
 
 error: redundant closure
-  --> tests/ui/eta.rs:317:18
+  --> tests/ui/eta.rs:318:18
    |
 LL |     takes_fn_mut(|| f());
    |                  ^^^^^^ help: replace the closure with the function itself: `&mut f`
 
 error: redundant closure
-  --> tests/ui/eta.rs:320:19
+  --> tests/ui/eta.rs:321:19
    |
 LL |     takes_fn_once(|| f());
    |                   ^^^^^^ help: replace the closure with the function itself: `&mut f`
 
 error: redundant closure
-  --> tests/ui/eta.rs:324:26
+  --> tests/ui/eta.rs:325:26
    |
 LL |     move || takes_fn_mut(|| f_used_once())
    |                          ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut f_used_once`
 
 error: redundant closure
-  --> tests/ui/eta.rs:336:19
+  --> tests/ui/eta.rs:337:19
    |
 LL |     array_opt.map(|a| a.as_slice());
    |                   ^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8; 3]>::as_slice`
 
 error: redundant closure
-  --> tests/ui/eta.rs:339:19
+  --> tests/ui/eta.rs:340:19
    |
 LL |     slice_opt.map(|s| s.len());
    |                   ^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8]>::len`
 
 error: redundant closure
-  --> tests/ui/eta.rs:342:17
+  --> tests/ui/eta.rs:343:17
    |
 LL |     ptr_opt.map(|p| p.is_null());
    |                 ^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<*const usize>::is_null`
 
 error: redundant closure
-  --> tests/ui/eta.rs:346:17
+  --> tests/ui/eta.rs:347:17
    |
 LL |     dyn_opt.map(|d| d.method_on_dyn());
    |                 ^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<dyn TestTrait>::method_on_dyn`
 
 error: redundant closure
-  --> tests/ui/eta.rs:406:19
+  --> tests/ui/eta.rs:407:19
    |
 LL |     let _ = f(&0, |x, y| f2(x, y));
    |                   ^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `f2`
 
 error: redundant closure
-  --> tests/ui/eta.rs:434:22
+  --> tests/ui/eta.rs:435:22
    |
 LL |             test.map(|t| t.method())
    |                      ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `Test::method`
 
 error: redundant closure
-  --> tests/ui/eta.rs:438:22
+  --> tests/ui/eta.rs:439:22
    |
 LL |             test.map(|t| t.method())
    |                      ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `super::Outer::method`
 
 error: redundant closure
-  --> tests/ui/eta.rs:451:18
+  --> tests/ui/eta.rs:452:18
    |
 LL |         test.map(|t| t.method())
    |                  ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `test_mod::Test::method`
 
 error: redundant closure
-  --> tests/ui/eta.rs:458:30
+  --> tests/ui/eta.rs:459:30
    |
 LL |                     test.map(|t| t.method())
    |                              ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `crate::issue_10854::d::Test::method`
 
 error: redundant closure
-  --> tests/ui/eta.rs:477:38
+  --> tests/ui/eta.rs:478:38
    |
 LL |         let x = Box::new(|| None.map(|x| f(x)));
    |                                      ^^^^^^^^ help: replace the closure with the function itself: `&f`
 
 error: redundant closure
-  --> tests/ui/eta.rs:481:38
+  --> tests/ui/eta.rs:482:38
    |
 LL |         let x = Box::new(|| None.map(|x| f(x)));
    |                                      ^^^^^^^^ help: replace the closure with the function itself: `f`
 
-error: aborting due to 33 previous errors
+error: redundant closure
+  --> tests/ui/eta.rs:499:35
+   |
+LL |         let _field = bind.or_else(|| get_default()).unwrap();
+   |                                   ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `get_default`
+
+error: aborting due to 34 previous errors
 
diff --git a/src/tools/clippy/tests/ui/excessive_precision.stderr b/src/tools/clippy/tests/ui/excessive_precision.stderr
index 6d8e166a649..81e4fb6765d 100644
--- a/src/tools/clippy/tests/ui/excessive_precision.stderr
+++ b/src/tools/clippy/tests/ui/excessive_precision.stderr
@@ -2,100 +2,179 @@ error: float has excessive precision
   --> tests/ui/excessive_precision.rs:20:26
    |
 LL |     const BAD32_1: f32 = 0.123_456_789_f32;
-   |                          ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_79_f32`
+   |                          ^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::excessive-precision` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::excessive_precision)]`
+help: consider changing the type or truncating it to
+   |
+LL |     const BAD32_1: f32 = 0.123_456_79_f32;
+   |                          ~~~~~~~~~~~~~~~~
 
 error: float has excessive precision
   --> tests/ui/excessive_precision.rs:21:26
    |
 LL |     const BAD32_2: f32 = 0.123_456_789;
-   |                          ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_79`
+   |                          ^^^^^^^^^^^^^
+   |
+help: consider changing the type or truncating it to
+   |
+LL |     const BAD32_2: f32 = 0.123_456_79;
+   |                          ~~~~~~~~~~~~
 
 error: float has excessive precision
   --> tests/ui/excessive_precision.rs:22:26
    |
 LL |     const BAD32_3: f32 = 0.100_000_000_000_1;
-   |                          ^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.1`
+   |                          ^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or truncating it to
+   |
+LL |     const BAD32_3: f32 = 0.1;
+   |                          ~~~
 
 error: float has excessive precision
   --> tests/ui/excessive_precision.rs:23:29
    |
 LL |     const BAD32_EDGE: f32 = 1.000_000_9;
-   |                             ^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.000_001`
+   |                             ^^^^^^^^^^^
+   |
+help: consider changing the type or truncating it to
+   |
+LL |     const BAD32_EDGE: f32 = 1.000_001;
+   |                             ~~~~~~~~~
 
 error: float has excessive precision
   --> tests/ui/excessive_precision.rs:27:26
    |
 LL |     const BAD64_3: f64 = 0.100_000_000_000_000_000_1;
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.1`
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or truncating it to
+   |
+LL |     const BAD64_3: f64 = 0.1;
+   |                          ~~~
 
 error: float has excessive precision
   --> tests/ui/excessive_precision.rs:30:22
    |
 LL |     println!("{:?}", 8.888_888_888_888_888_888_888);
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `8.888_888_888_888_89`
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or truncating it to
+   |
+LL |     println!("{:?}", 8.888_888_888_888_89);
+   |                      ~~~~~~~~~~~~~~~~~~~~
 
 error: float has excessive precision
   --> tests/ui/excessive_precision.rs:41:22
    |
 LL |     let bad32: f32 = 1.123_456_789;
-   |                      ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8`
+   |                      ^^^^^^^^^^^^^
+   |
+help: consider changing the type or truncating it to
+   |
+LL |     let bad32: f32 = 1.123_456_8;
+   |                      ~~~~~~~~~~~
 
 error: float has excessive precision
   --> tests/ui/excessive_precision.rs:42:26
    |
 LL |     let bad32_suf: f32 = 1.123_456_789_f32;
-   |                          ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8_f32`
+   |                          ^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or truncating it to
+   |
+LL |     let bad32_suf: f32 = 1.123_456_8_f32;
+   |                          ~~~~~~~~~~~~~~~
 
 error: float has excessive precision
   --> tests/ui/excessive_precision.rs:43:21
    |
 LL |     let bad32_inf = 1.123_456_789_f32;
-   |                     ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8_f32`
+   |                     ^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or truncating it to
+   |
+LL |     let bad32_inf = 1.123_456_8_f32;
+   |                     ~~~~~~~~~~~~~~~
 
 error: float has excessive precision
   --> tests/ui/excessive_precision.rs:53:36
    |
 LL |     let bad_vec32: Vec<f32> = vec![0.123_456_789];
-   |                                    ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_79`
+   |                                    ^^^^^^^^^^^^^
+   |
+help: consider changing the type or truncating it to
+   |
+LL |     let bad_vec32: Vec<f32> = vec![0.123_456_79];
+   |                                    ~~~~~~~~~~~~
 
 error: float has excessive precision
   --> tests/ui/excessive_precision.rs:54:36
    |
 LL |     let bad_vec64: Vec<f64> = vec![0.123_456_789_123_456_789];
-   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_123_456_78`
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or truncating it to
+   |
+LL |     let bad_vec64: Vec<f64> = vec![0.123_456_789_123_456_78];
+   |                                    ~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: float has excessive precision
   --> tests/ui/excessive_precision.rs:58:24
    |
 LL |     let bad_e32: f32 = 1.123_456_788_888e-10;
-   |                        ^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8e-10`
+   |                        ^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or truncating it to
+   |
+LL |     let bad_e32: f32 = 1.123_456_8e-10;
+   |                        ~~~~~~~~~~~~~~~
 
 error: float has excessive precision
   --> tests/ui/excessive_precision.rs:61:27
    |
 LL |     let bad_bige32: f32 = 1.123_456_788_888E-10;
-   |                           ^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8E-10`
+   |                           ^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or truncating it to
+   |
+LL |     let bad_bige32: f32 = 1.123_456_8E-10;
+   |                           ~~~~~~~~~~~~~~~
 
 error: float has excessive precision
   --> tests/ui/excessive_precision.rs:70:13
    |
 LL |     let _ = 2.225_073_858_507_201_1e-308_f64;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `2.225_073_858_507_201e-308_f64`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or truncating it to
+   |
+LL |     let _ = 2.225_073_858_507_201e-308_f64;
+   |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: float has excessive precision
   --> tests/ui/excessive_precision.rs:73:13
    |
 LL |     let _ = 1.000_000_000_000_001e-324_f64;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0_f64`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or truncating it to
+   |
+LL |     let _ = 0_f64;
+   |             ~~~~~
 
 error: float has excessive precision
   --> tests/ui/excessive_precision.rs:83:20
    |
 LL |     const _: f64 = 3.0000000000000000e+00;
-   |                    ^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `3.0`
+   |                    ^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or truncating it to
+   |
+LL |     const _: f64 = 3.0;
+   |                    ~~~
 
 error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui/explicit_counter_loop.rs b/src/tools/clippy/tests/ui/explicit_counter_loop.rs
index c25e79a3617..28b477b6921 100644
--- a/src/tools/clippy/tests/ui/explicit_counter_loop.rs
+++ b/src/tools/clippy/tests/ui/explicit_counter_loop.rs
@@ -278,3 +278,16 @@ mod issue_10058 {
         }
     }
 }
+
+mod issue_13123 {
+    pub fn test() {
+        let mut vec = vec![1, 2, 3, 4];
+        let mut _index = 0;
+        'label: for v in vec {
+            _index += 1;
+            if v == 1 {
+                break 'label;
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/explicit_counter_loop.stderr b/src/tools/clippy/tests/ui/explicit_counter_loop.stderr
index e28f8783f9c..1b2d1f8570a 100644
--- a/src/tools/clippy/tests/ui/explicit_counter_loop.stderr
+++ b/src/tools/clippy/tests/ui/explicit_counter_loop.stderr
@@ -57,5 +57,11 @@ LL |         for _item in slice {
    |
    = note: `idx_u32` is of type `u32`, making it ineligible for `Iterator::enumerate`
 
-error: aborting due to 9 previous errors
+error: the variable `_index` is used as a loop counter
+  --> tests/ui/explicit_counter_loop.rs:286:9
+   |
+LL |         'label: for v in vec {
+   |         ^^^^^^^^^^^^^^^^^^^^ help: consider using: `'label: for (_index, v) in vec.into_iter().enumerate()`
+
+error: aborting due to 10 previous errors
 
diff --git a/src/tools/clippy/tests/ui/fn_to_numeric_cast_any.stderr b/src/tools/clippy/tests/ui/fn_to_numeric_cast_any.stderr
index e5bb8d13269..a05b7138bc9 100644
--- a/src/tools/clippy/tests/ui/fn_to_numeric_cast_any.stderr
+++ b/src/tools/clippy/tests/ui/fn_to_numeric_cast_any.stderr
@@ -2,106 +2,190 @@ error: casting function pointer `foo` to `i8`
   --> tests/ui/fn_to_numeric_cast_any.rs:23:13
    |
 LL |     let _ = foo as i8;
-   |             ^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i8`
+   |             ^^^^^^^^^
    |
    = note: `-D clippy::fn-to-numeric-cast-any` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::fn_to_numeric_cast_any)]`
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as i8;
+   |             ~~~~~~~~~~~
 
 error: casting function pointer `foo` to `i16`
   --> tests/ui/fn_to_numeric_cast_any.rs:26:13
    |
 LL |     let _ = foo as i16;
-   |             ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i16`
+   |             ^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as i16;
+   |             ~~~~~~~~~~~~
 
 error: casting function pointer `foo` to `i32`
   --> tests/ui/fn_to_numeric_cast_any.rs:28:13
    |
 LL |     let _ = foo as i32;
-   |             ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i32`
+   |             ^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as i32;
+   |             ~~~~~~~~~~~~
 
 error: casting function pointer `foo` to `i64`
   --> tests/ui/fn_to_numeric_cast_any.rs:30:13
    |
 LL |     let _ = foo as i64;
-   |             ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i64`
+   |             ^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as i64;
+   |             ~~~~~~~~~~~~
 
 error: casting function pointer `foo` to `i128`
   --> tests/ui/fn_to_numeric_cast_any.rs:32:13
    |
 LL |     let _ = foo as i128;
-   |             ^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i128`
+   |             ^^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as i128;
+   |             ~~~~~~~~~~~~~
 
 error: casting function pointer `foo` to `isize`
   --> tests/ui/fn_to_numeric_cast_any.rs:34:13
    |
 LL |     let _ = foo as isize;
-   |             ^^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as isize`
+   |             ^^^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as isize;
+   |             ~~~~~~~~~~~~~~
 
 error: casting function pointer `foo` to `u8`
   --> tests/ui/fn_to_numeric_cast_any.rs:37:13
    |
 LL |     let _ = foo as u8;
-   |             ^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u8`
+   |             ^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as u8;
+   |             ~~~~~~~~~~~
 
 error: casting function pointer `foo` to `u16`
   --> tests/ui/fn_to_numeric_cast_any.rs:39:13
    |
 LL |     let _ = foo as u16;
-   |             ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u16`
+   |             ^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as u16;
+   |             ~~~~~~~~~~~~
 
 error: casting function pointer `foo` to `u32`
   --> tests/ui/fn_to_numeric_cast_any.rs:41:13
    |
 LL |     let _ = foo as u32;
-   |             ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u32`
+   |             ^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as u32;
+   |             ~~~~~~~~~~~~
 
 error: casting function pointer `foo` to `u64`
   --> tests/ui/fn_to_numeric_cast_any.rs:43:13
    |
 LL |     let _ = foo as u64;
-   |             ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u64`
+   |             ^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as u64;
+   |             ~~~~~~~~~~~~
 
 error: casting function pointer `foo` to `u128`
   --> tests/ui/fn_to_numeric_cast_any.rs:45:13
    |
 LL |     let _ = foo as u128;
-   |             ^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u128`
+   |             ^^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as u128;
+   |             ~~~~~~~~~~~~~
 
 error: casting function pointer `foo` to `usize`
   --> tests/ui/fn_to_numeric_cast_any.rs:47:13
    |
 LL |     let _ = foo as usize;
-   |             ^^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as usize`
+   |             ^^^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as usize;
+   |             ~~~~~~~~~~~~~~
 
 error: casting function pointer `Struct::static_method` to `usize`
   --> tests/ui/fn_to_numeric_cast_any.rs:52:13
    |
 LL |     let _ = Struct::static_method as usize;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to invoke the function?: `Struct::static_method() as usize`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = Struct::static_method() as usize;
+   |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting function pointer `f` to `usize`
   --> tests/ui/fn_to_numeric_cast_any.rs:57:5
    |
 LL |     f as usize
-   |     ^^^^^^^^^^ help: did you mean to invoke the function?: `f() as usize`
+   |     ^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     f() as usize
+   |
 
 error: casting function pointer `T::static_method` to `usize`
   --> tests/ui/fn_to_numeric_cast_any.rs:62:5
    |
 LL |     T::static_method as usize
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to invoke the function?: `T::static_method() as usize`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     T::static_method() as usize
+   |
 
 error: casting function pointer `(clos as fn(u32) -> u32)` to `usize`
   --> tests/ui/fn_to_numeric_cast_any.rs:69:13
    |
 LL |     let _ = (clos as fn(u32) -> u32) as usize;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to invoke the function?: `(clos as fn(u32) -> u32)() as usize`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = (clos as fn(u32) -> u32)() as usize;
+   |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting function pointer `foo` to `*const ()`
   --> tests/ui/fn_to_numeric_cast_any.rs:74:13
    |
 LL |     let _ = foo as *const ();
-   |             ^^^^^^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as *const ()`
+   |             ^^^^^^^^^^^^^^^^
+   |
+help: did you mean to invoke the function?
+   |
+LL |     let _ = foo() as *const ();
+   |             ~~~~~~~~~~~~~~~~~~
 
 error: aborting due to 17 previous errors
 
diff --git a/src/tools/clippy/tests/ui/for_kv_map.fixed b/src/tools/clippy/tests/ui/for_kv_map.fixed
index a2112d7b730..1733b29128f 100644
--- a/src/tools/clippy/tests/ui/for_kv_map.fixed
+++ b/src/tools/clippy/tests/ui/for_kv_map.fixed
@@ -40,6 +40,16 @@ fn main() {
         let _k = k;
     }
 
+    let m: HashMap<u64, u64> = HashMap::new();
+    let rm = &m;
+    'label: for k in rm.keys() {
+        //~^ ERROR: you seem to want to iterate on a map's keys
+        let _k = k;
+        if *k == 0u64 {
+            break 'label;
+        }
+    }
+
     // The following should not produce warnings.
 
     let m: HashMap<u64, u64> = HashMap::new();
diff --git a/src/tools/clippy/tests/ui/for_kv_map.rs b/src/tools/clippy/tests/ui/for_kv_map.rs
index 1b7959b8f92..de465a7c8e6 100644
--- a/src/tools/clippy/tests/ui/for_kv_map.rs
+++ b/src/tools/clippy/tests/ui/for_kv_map.rs
@@ -40,6 +40,16 @@ fn main() {
         let _k = k;
     }
 
+    let m: HashMap<u64, u64> = HashMap::new();
+    let rm = &m;
+    'label: for (k, _value) in rm {
+        //~^ ERROR: you seem to want to iterate on a map's keys
+        let _k = k;
+        if *k == 0u64 {
+            break 'label;
+        }
+    }
+
     // The following should not produce warnings.
 
     let m: HashMap<u64, u64> = HashMap::new();
diff --git a/src/tools/clippy/tests/ui/for_kv_map.stderr b/src/tools/clippy/tests/ui/for_kv_map.stderr
index f4ce473d095..adcc3ab8fdb 100644
--- a/src/tools/clippy/tests/ui/for_kv_map.stderr
+++ b/src/tools/clippy/tests/ui/for_kv_map.stderr
@@ -55,5 +55,16 @@ help: use the corresponding method
 LL |     for k in rm.keys() {
    |         ~    ~~~~~~~~~
 
-error: aborting due to 5 previous errors
+error: you seem to want to iterate on a map's keys
+  --> tests/ui/for_kv_map.rs:45:32
+   |
+LL |     'label: for (k, _value) in rm {
+   |                                ^^
+   |
+help: use the corresponding method
+   |
+LL |     'label: for k in rm.keys() {
+   |                 ~    ~~~~~~~~~
+
+error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui/get_unwrap.stderr b/src/tools/clippy/tests/ui/get_unwrap.stderr
index a08b6657dcc..0f8b279da1e 100644
--- a/src/tools/clippy/tests/ui/get_unwrap.stderr
+++ b/src/tools/clippy/tests/ui/get_unwrap.stderr
@@ -1,14 +1,18 @@
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui/get_unwrap.rs:37:17
    |
 LL |         let _ = boxed_slice.get(1).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&boxed_slice[1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
   --> tests/ui/get_unwrap.rs:9:9
    |
 LL | #![deny(clippy::get_unwrap)]
    |         ^^^^^^^^^^^^^^^^^^
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &boxed_slice[1];
+   |                 ~~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:37:17
@@ -21,11 +25,16 @@ LL |         let _ = boxed_slice.get(1).unwrap();
    = note: `-D clippy::unwrap-used` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::unwrap_used)]`
 
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui/get_unwrap.rs:38:17
    |
 LL |         let _ = some_slice.get(0).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_slice[0]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &some_slice[0];
+   |                 ~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:38:17
@@ -36,11 +45,16 @@ LL |         let _ = some_slice.get(0).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a Vec
   --> tests/ui/get_unwrap.rs:39:17
    |
 LL |         let _ = some_vec.get(0).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vec[0]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &some_vec[0];
+   |                 ~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:39:17
@@ -51,11 +65,16 @@ LL |         let _ = some_vec.get(0).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a VecDeque
   --> tests/ui/get_unwrap.rs:40:17
    |
 LL |         let _ = some_vecdeque.get(0).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vecdeque[0]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &some_vecdeque[0];
+   |                 ~~~~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:40:17
@@ -66,11 +85,16 @@ LL |         let _ = some_vecdeque.get(0).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a HashMap
   --> tests/ui/get_unwrap.rs:41:17
    |
 LL |         let _ = some_hashmap.get(&1).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_hashmap[&1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &some_hashmap[&1];
+   |                 ~~~~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:41:17
@@ -81,11 +105,16 @@ LL |         let _ = some_hashmap.get(&1).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a BTreeMap
   --> tests/ui/get_unwrap.rs:42:17
    |
 LL |         let _ = some_btreemap.get(&1).unwrap();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_btreemap[&1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = &some_btreemap[&1];
+   |                 ~~~~~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:42:17
@@ -96,11 +125,16 @@ LL |         let _ = some_btreemap.get(&1).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui/get_unwrap.rs:46:21
    |
 LL |         let _: u8 = *boxed_slice.get(1).unwrap();
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[1]`
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _: u8 = boxed_slice[1];
+   |                     ~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:46:22
@@ -111,11 +145,16 @@ LL |         let _: u8 = *boxed_slice.get(1).unwrap();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a slice
   --> tests/ui/get_unwrap.rs:51:9
    |
 LL |         *boxed_slice.get_mut(0).unwrap() = 1;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[0]`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         boxed_slice[0] = 1;
+   |         ~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:51:10
@@ -126,11 +165,16 @@ LL |         *boxed_slice.get_mut(0).unwrap() = 1;
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a slice
   --> tests/ui/get_unwrap.rs:52:9
    |
 LL |         *some_slice.get_mut(0).unwrap() = 1;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_slice[0]`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         some_slice[0] = 1;
+   |         ~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:52:10
@@ -141,11 +185,16 @@ LL |         *some_slice.get_mut(0).unwrap() = 1;
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a Vec
   --> tests/ui/get_unwrap.rs:53:9
    |
 LL |         *some_vec.get_mut(0).unwrap() = 1;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0]`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         some_vec[0] = 1;
+   |         ~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:53:10
@@ -156,11 +205,16 @@ LL |         *some_vec.get_mut(0).unwrap() = 1;
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a VecDeque
   --> tests/ui/get_unwrap.rs:54:9
    |
 LL |         *some_vecdeque.get_mut(0).unwrap() = 1;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vecdeque[0]`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         some_vecdeque[0] = 1;
+   |         ~~~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:54:10
@@ -171,11 +225,16 @@ LL |         *some_vecdeque.get_mut(0).unwrap() = 1;
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a Vec
   --> tests/ui/get_unwrap.rs:66:17
    |
 LL |         let _ = some_vec.get(0..1).unwrap().to_vec();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = some_vec[0..1].to_vec();
+   |                 ~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:66:17
@@ -186,11 +245,16 @@ LL |         let _ = some_vec.get(0..1).unwrap().to_vec();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a Vec
   --> tests/ui/get_unwrap.rs:67:17
    |
 LL |         let _ = some_vec.get_mut(0..1).unwrap().to_vec();
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _ = some_vec[0..1].to_vec();
+   |                 ~~~~~~~~~~~~~~
 
 error: used `unwrap()` on an `Option` value
   --> tests/ui/get_unwrap.rs:67:17
@@ -201,29 +265,49 @@ LL |         let _ = some_vec.get_mut(0..1).unwrap().to_vec();
    = note: if this value is `None`, it will panic
    = help: consider using `expect()` to provide a better panic message
 
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui/get_unwrap.rs:77:24
    |
 LL |         let _x: &i32 = f.get(1 + 2).unwrap();
-   |                        ^^^^^^^^^^^^^^^^^^^^^ help: try: `&f[1 + 2]`
+   |                        ^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _x: &i32 = &f[1 + 2];
+   |                        ~~~~~~~~~
 
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui/get_unwrap.rs:80:18
    |
 LL |         let _x = f.get(1 + 2).unwrap().to_string();
-   |                  ^^^^^^^^^^^^^^^^^^^^^ help: try: `f[1 + 2]`
+   |                  ^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _x = f[1 + 2].to_string();
+   |                  ~~~~~~~~
 
-error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get().unwrap()` on a slice
   --> tests/ui/get_unwrap.rs:83:18
    |
 LL |         let _x = f.get(1 + 2).unwrap().abs();
-   |                  ^^^^^^^^^^^^^^^^^^^^^ help: try: `f[1 + 2]`
+   |                  ^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |         let _x = f[1 + 2].abs();
+   |                  ~~~~~~~~
 
-error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
+error: called `.get_mut().unwrap()` on a slice
   --> tests/ui/get_unwrap.rs:100:33
    |
 LL |                         let b = rest.get_mut(linidx(j, k) - linidx(i, k) - 1).unwrap();
-   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut rest[linidx(j, k) - linidx(i, k) - 1]`
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: using `[]` is clearer and more concise
+   |
+LL |                         let b = &mut rest[linidx(j, k) - linidx(i, k) - 1];
+   |                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: aborting due to 30 previous errors
 
diff --git a/src/tools/clippy/tests/ui/if_let_mutex.rs b/src/tools/clippy/tests/ui/if_let_mutex.rs
index cb6915e0eba..bb0eadfca1c 100644
--- a/src/tools/clippy/tests/ui/if_let_mutex.rs
+++ b/src/tools/clippy/tests/ui/if_let_mutex.rs
@@ -1,4 +1,5 @@
 #![warn(clippy::if_let_mutex)]
+#![allow(clippy::redundant_pattern_matching)]
 
 use std::ops::Deref;
 use std::sync::Mutex;
@@ -50,4 +51,12 @@ fn mutex_ref(mutex: &Mutex<i32>) {
     };
 }
 
+fn multiple_mutexes(m1: &Mutex<()>, m2: &Mutex<()>) {
+    if let Ok(_) = m1.lock() {
+        m2.lock();
+    } else {
+        m1.lock();
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/if_let_mutex.stderr b/src/tools/clippy/tests/ui/if_let_mutex.stderr
index 6e0115c23af..45df4ac4d67 100644
--- a/src/tools/clippy/tests/ui/if_let_mutex.stderr
+++ b/src/tools/clippy/tests/ui/if_let_mutex.stderr
@@ -1,5 +1,5 @@
 error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock
-  --> tests/ui/if_let_mutex.rs:10:5
+  --> tests/ui/if_let_mutex.rs:11:5
    |
 LL |       if let Err(locked) = m.lock() {
    |       ^                    - this Mutex will remain locked for the entire `if let`-block...
@@ -19,7 +19,7 @@ LL | |     };
    = help: to override `-D warnings` add `#[allow(clippy::if_let_mutex)]`
 
 error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock
-  --> tests/ui/if_let_mutex.rs:23:5
+  --> tests/ui/if_let_mutex.rs:24:5
    |
 LL |       if let Some(locked) = m.lock().unwrap().deref() {
    |       ^                     - this Mutex will remain locked for the entire `if let`-block...
@@ -37,7 +37,7 @@ LL | |     };
    = help: move the lock call outside of the `if let ...` expression
 
 error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock
-  --> tests/ui/if_let_mutex.rs:45:5
+  --> tests/ui/if_let_mutex.rs:46:5
    |
 LL |       if let Ok(i) = mutex.lock() {
    |       ^              ----- this Mutex will remain locked for the entire `if let`-block...
@@ -53,5 +53,21 @@ LL | |     };
    |
    = help: move the lock call outside of the `if let ...` expression
 
-error: aborting due to 3 previous errors
+error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock
+  --> tests/ui/if_let_mutex.rs:55:5
+   |
+LL |       if let Ok(_) = m1.lock() {
+   |       ^              -- this Mutex will remain locked for the entire `if let`-block...
+   |  _____|
+   | |
+LL | |         m2.lock();
+LL | |     } else {
+LL | |         m1.lock();
+   | |         -- ... and is tried to lock again here, which will always deadlock.
+LL | |     }
+   | |_____^
+   |
+   = help: move the lock call outside of the `if let ...` expression
+
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none.fixed b/src/tools/clippy/tests/ui/if_then_some_else_none.fixed
new file mode 100644
index 00000000000..ad13372a68b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/if_then_some_else_none.fixed
@@ -0,0 +1,119 @@
+#![warn(clippy::if_then_some_else_none)]
+#![allow(clippy::redundant_pattern_matching, clippy::unnecessary_lazy_evaluations)]
+
+fn main() {
+    // Should issue an error.
+    let _ = foo().then(||  { println!("true!"); "foo" });
+
+    // Should issue an error when macros are used.
+    let _ = matches!(true, true).then(||  { println!("true!"); matches!(true, false) });
+
+    // Should issue an error. Binary expression `o < 32` should be parenthesized.
+    let x = Some(5);
+    let _ = x.and_then(|o| (o < 32).then_some(o));
+    //~^ ERROR: this could be simplified with `bool::then_some`
+
+    // Should issue an error. Unary expression `!x` should be parenthesized.
+    let x = true;
+    let _ = (!x).then_some(0);
+    //~^ ERROR: this could be simplified with `bool::then_some`
+
+    // Should not issue an error since the `else` block has a statement besides `None`.
+    let _ = if foo() {
+        println!("true!");
+        Some("foo")
+    } else {
+        eprintln!("false...");
+        None
+    };
+
+    // Should not issue an error since there are more than 2 blocks in the if-else chain.
+    let _ = if foo() {
+        println!("foo true!");
+        Some("foo")
+    } else if bar() {
+        println!("bar true!");
+        Some("bar")
+    } else {
+        None
+    };
+
+    let _ = if foo() {
+        println!("foo true!");
+        Some("foo")
+    } else {
+        bar().then(|| {
+            println!("bar true!");
+            "bar"
+        })
+    };
+
+    // Should not issue an error since the `then` block has `None`, not `Some`.
+    let _ = if foo() { None } else { Some("foo is false") };
+
+    // Should not issue an error since the `else` block doesn't use `None` directly.
+    let _ = if foo() { Some("foo is true") } else { into_none() };
+
+    // Should not issue an error since the `then` block doesn't use `Some` directly.
+    let _ = if foo() { into_some("foo") } else { None };
+}
+
+#[clippy::msrv = "1.49"]
+fn _msrv_1_49() {
+    // `bool::then` was stabilized in 1.50. Do not lint this
+    let _ = if foo() {
+        println!("true!");
+        Some(149)
+    } else {
+        None
+    };
+}
+
+#[clippy::msrv = "1.50"]
+fn _msrv_1_50() {
+    let _ = foo().then(||  { println!("true!"); 150 });
+}
+
+fn foo() -> bool {
+    unimplemented!()
+}
+
+fn bar() -> bool {
+    unimplemented!()
+}
+
+fn into_some<T>(v: T) -> Option<T> {
+    Some(v)
+}
+
+fn into_none<T>() -> Option<T> {
+    None
+}
+
+// Should not warn
+fn f(b: bool, v: Option<()>) -> Option<()> {
+    if b {
+        v?; // This is a potential early return, is not equivalent with `bool::then`
+
+        Some(())
+    } else {
+        None
+    }
+}
+
+fn issue11394(b: bool, v: Result<(), ()>) -> Result<(), ()> {
+    let x = if b {
+        #[allow(clippy::let_unit_value)]
+        let _ = v?;
+        Some(())
+    } else {
+        None
+    };
+
+    Ok(())
+}
+
+const fn issue12103(x: u32) -> Option<u32> {
+    // Should not issue an error in `const` context
+    if x > 42 { Some(150) } else { None }
+}
diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none.rs b/src/tools/clippy/tests/ui/if_then_some_else_none.rs
index ccde154bd56..73edbb7da2a 100644
--- a/src/tools/clippy/tests/ui/if_then_some_else_none.rs
+++ b/src/tools/clippy/tests/ui/if_then_some_else_none.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::if_then_some_else_none)]
-#![allow(clippy::redundant_pattern_matching)]
+#![allow(clippy::redundant_pattern_matching, clippy::unnecessary_lazy_evaluations)]
 
 fn main() {
     // Should issue an error.
diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none.stderr b/src/tools/clippy/tests/ui/if_then_some_else_none.stderr
index e0a95aebdc1..aed01e026cb 100644
--- a/src/tools/clippy/tests/ui/if_then_some_else_none.stderr
+++ b/src/tools/clippy/tests/ui/if_then_some_else_none.stderr
@@ -9,9 +9,8 @@ LL | |         Some("foo")
 LL | |     } else {
 LL | |         None
 LL | |     };
-   | |_____^
+   | |_____^ help: try: `foo().then(||  { println!("true!"); "foo" })`
    |
-   = help: consider using `bool::then` like: `foo().then(|| { /* snippet */ "foo" })`
    = note: `-D clippy::if-then-some-else-none` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::if_then_some_else_none)]`
 
@@ -26,25 +25,19 @@ LL | |         Some(matches!(true, false))
 LL | |     } else {
 LL | |         None
 LL | |     };
-   | |_____^
-   |
-   = help: consider using `bool::then` like: `matches!(true, true).then(|| { /* snippet */ matches!(true, false) })`
+   | |_____^ help: try: `matches!(true, true).then(||  { println!("true!"); matches!(true, false) })`
 
 error: this could be simplified with `bool::then_some`
   --> tests/ui/if_then_some_else_none.rs:25:28
    |
 LL |     let _ = x.and_then(|o| if o < 32 { Some(o) } else { None });
-   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider using `bool::then_some` like: `(o < 32).then_some(o)`
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(o < 32).then_some(o)`
 
 error: this could be simplified with `bool::then_some`
   --> tests/ui/if_then_some_else_none.rs:30:13
    |
 LL |     let _ = if !x { Some(0) } else { None };
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider using `bool::then_some` like: `(!x).then_some(0)`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(!x).then_some(0)`
 
 error: this could be simplified with `bool::then`
   --> tests/ui/if_then_some_else_none.rs:86:13
@@ -57,9 +50,7 @@ LL | |         Some(150)
 LL | |     } else {
 LL | |         None
 LL | |     };
-   | |_____^
-   |
-   = help: consider using `bool::then` like: `foo().then(|| { /* snippet */ 150 })`
+   | |_____^ help: try: `foo().then(||  { println!("true!"); 150 })`
 
 error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/implicit_hasher.fixed b/src/tools/clippy/tests/ui/implicit_hasher.fixed
new file mode 100644
index 00000000000..2d6dc0274cf
--- /dev/null
+++ b/src/tools/clippy/tests/ui/implicit_hasher.fixed
@@ -0,0 +1,102 @@
+//@aux-build:proc_macros.rs
+#![deny(clippy::implicit_hasher)]
+
+#[macro_use]
+extern crate proc_macros;
+
+use std::cmp::Eq;
+use std::collections::{HashMap, HashSet};
+use std::hash::{BuildHasher, Hash};
+
+pub trait Foo<T>: Sized {
+    fn make() -> (Self, Self);
+}
+
+impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<i8> for HashMap<K, V, S> {
+    fn make() -> (Self, Self) {
+        // OK, don't suggest to modify these
+        let _: HashMap<i32, i32> = HashMap::new();
+        let _: HashSet<i32> = HashSet::new();
+
+        (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default()))
+    }
+}
+impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<i8> for (HashMap<K, V, S>,) {
+    fn make() -> (Self, Self) {
+        ((HashMap::default(),), (HashMap::with_capacity_and_hasher(10, Default::default()),))
+    }
+}
+impl<S: ::std::hash::BuildHasher + Default> Foo<i16> for HashMap<String, String, S> {
+    fn make() -> (Self, Self) {
+        (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default()))
+    }
+}
+
+impl<K: Hash + Eq, V, S: BuildHasher + Default> Foo<i32> for HashMap<K, V, S> {
+    fn make() -> (Self, Self) {
+        (HashMap::default(), HashMap::with_capacity_and_hasher(10, S::default()))
+    }
+}
+impl<S: BuildHasher + Default> Foo<i64> for HashMap<String, String, S> {
+    fn make() -> (Self, Self) {
+        (HashMap::default(), HashMap::with_capacity_and_hasher(10, S::default()))
+    }
+}
+
+impl<T: Hash + Eq, S: ::std::hash::BuildHasher + Default> Foo<i8> for HashSet<T, S> {
+    fn make() -> (Self, Self) {
+        (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default::default()))
+    }
+}
+impl<S: ::std::hash::BuildHasher + Default> Foo<i16> for HashSet<String, S> {
+    fn make() -> (Self, Self) {
+        (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default::default()))
+    }
+}
+
+impl<T: Hash + Eq, S: BuildHasher + Default> Foo<i32> for HashSet<T, S> {
+    fn make() -> (Self, Self) {
+        (HashSet::default(), HashSet::with_capacity_and_hasher(10, S::default()))
+    }
+}
+impl<S: BuildHasher + Default> Foo<i64> for HashSet<String, S> {
+    fn make() -> (Self, Self) {
+        (HashSet::default(), HashSet::with_capacity_and_hasher(10, S::default()))
+    }
+}
+
+pub fn map<S: ::std::hash::BuildHasher>(map: &mut HashMap<i32, i32, S>) {}
+
+pub fn set<S: ::std::hash::BuildHasher>(set: &mut HashSet<i32, S>) {}
+
+#[inline_macros]
+pub mod gen {
+    use super::*;
+    inline! {
+        impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<u8> for HashMap<K, V, S> {
+            fn make() -> (Self, Self) {
+                (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default()))
+            }
+        }
+
+        pub fn bar(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
+    }
+}
+
+// When the macro is in a different file, the suggestion spans can't be combined properly
+// and should not cause an ICE
+// See #2707
+#[macro_use]
+#[path = "auxiliary/test_macro.rs"]
+pub mod test_macro;
+__implicit_hasher_test_macro!(impl<K, V> for HashMap<K, V> where V: test_macro::A);
+
+// #4260
+external! {
+    pub fn f(input: &HashMap<u32, u32>) {}
+}
+
+// #7712
+pub async fn election_vote<S: ::std::hash::BuildHasher>(_data: HashMap<i32, i32, S>) {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/implicit_hasher.rs b/src/tools/clippy/tests/ui/implicit_hasher.rs
index f7cd541741b..0a334357bd1 100644
--- a/src/tools/clippy/tests/ui/implicit_hasher.rs
+++ b/src/tools/clippy/tests/ui/implicit_hasher.rs
@@ -1,11 +1,8 @@
 //@aux-build:proc_macros.rs
-//@no-rustfix
 #![deny(clippy::implicit_hasher)]
-#![allow(unused)]
 
 #[macro_use]
 extern crate proc_macros;
-use proc_macros::external;
 
 use std::cmp::Eq;
 use std::collections::{HashMap, HashSet};
@@ -68,9 +65,11 @@ impl<S: BuildHasher + Default> Foo<i64> for HashSet<String, S> {
     }
 }
 
-pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
+pub fn map(map: &mut HashMap<i32, i32>) {}
 
-#[proc_macros::inline_macros]
+pub fn set(set: &mut HashSet<i32>) {}
+
+#[inline_macros]
 pub mod gen {
     use super::*;
     inline! {
diff --git a/src/tools/clippy/tests/ui/implicit_hasher.stderr b/src/tools/clippy/tests/ui/implicit_hasher.stderr
index a3df8edf389..48c6ebc209c 100644
--- a/src/tools/clippy/tests/ui/implicit_hasher.stderr
+++ b/src/tools/clippy/tests/ui/implicit_hasher.stderr
@@ -1,40 +1,121 @@
-error: `proc-macro` crate types currently cannot export any items other than functions tagged with `#[proc_macro]`, `#[proc_macro_derive]`, or `#[proc_macro_attribute]`
-  --> tests/ui/implicit_hasher.rs:14:1
+error: impl for `HashMap` should be generalized over different hashers
+  --> tests/ui/implicit_hasher.rs:15:35
+   |
+LL | impl<K: Hash + Eq, V> Foo<i8> for HashMap<K, V> {
+   |                                   ^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> tests/ui/implicit_hasher.rs:2:9
+   |
+LL | #![deny(clippy::implicit_hasher)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^
+help: add a type parameter for `BuildHasher`
+   |
+LL ~ impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<i8> for HashMap<K, V, S> {
+LL |     fn make() -> (Self, Self) {
+...
+LL |
+LL ~         (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default()))
+   |
+
+error: impl for `HashMap` should be generalized over different hashers
+  --> tests/ui/implicit_hasher.rs:24:36
+   |
+LL | impl<K: Hash + Eq, V> Foo<i8> for (HashMap<K, V>,) {
+   |                                    ^^^^^^^^^^^^^
+   |
+help: add a type parameter for `BuildHasher`
+   |
+LL ~ impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<i8> for (HashMap<K, V, S>,) {
+LL |     fn make() -> (Self, Self) {
+LL ~         ((HashMap::default(),), (HashMap::with_capacity_and_hasher(10, Default::default()),))
+   |
+
+error: impl for `HashMap` should be generalized over different hashers
+  --> tests/ui/implicit_hasher.rs:29:19
+   |
+LL | impl Foo<i16> for HashMap<String, String> {
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: add a type parameter for `BuildHasher`
+   |
+LL ~ impl<S: ::std::hash::BuildHasher + Default> Foo<i16> for HashMap<String, String, S> {
+LL |     fn make() -> (Self, Self) {
+LL ~         (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default()))
+   |
+
+error: impl for `HashSet` should be generalized over different hashers
+  --> tests/ui/implicit_hasher.rs:46:32
+   |
+LL | impl<T: Hash + Eq> Foo<i8> for HashSet<T> {
+   |                                ^^^^^^^^^^
+   |
+help: add a type parameter for `BuildHasher`
+   |
+LL ~ impl<T: Hash + Eq, S: ::std::hash::BuildHasher + Default> Foo<i8> for HashSet<T, S> {
+LL |     fn make() -> (Self, Self) {
+LL ~         (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default::default()))
    |
-LL | pub trait Foo<T>: Sized {
-   | ^^^^^^^^^^^^^^^^^^^^^^^
 
-error: `proc-macro` crate types currently cannot export any items other than functions tagged with `#[proc_macro]`, `#[proc_macro_derive]`, or `#[proc_macro_attribute]`
-  --> tests/ui/implicit_hasher.rs:71:1
+error: impl for `HashSet` should be generalized over different hashers
+  --> tests/ui/implicit_hasher.rs:51:19
+   |
+LL | impl Foo<i16> for HashSet<String> {
+   |                   ^^^^^^^^^^^^^^^
+   |
+help: add a type parameter for `BuildHasher`
+   |
+LL ~ impl<S: ::std::hash::BuildHasher + Default> Foo<i16> for HashSet<String, S> {
+LL |     fn make() -> (Self, Self) {
+LL ~         (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default::default()))
    |
-LL | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: `proc-macro` crate types currently cannot export any items other than functions tagged with `#[proc_macro]`, `#[proc_macro_derive]`, or `#[proc_macro_attribute]`
-  --> tests/ui/implicit_hasher.rs:74:1
+error: parameter of type `HashMap` should be generalized over different hashers
+  --> tests/ui/implicit_hasher.rs:68:22
+   |
+LL | pub fn map(map: &mut HashMap<i32, i32>) {}
+   |                      ^^^^^^^^^^^^^^^^^
    |
-LL | pub mod gen {
-   | ^^^^^^^^^^^
+help: add a type parameter for `BuildHasher`
+   |
+LL | pub fn map<S: ::std::hash::BuildHasher>(map: &mut HashMap<i32, i32, S>) {}
+   |           +++++++++++++++++++++++++++++           ~~~~~~~~~~~~~~~~~~~~
 
-error: `proc-macro` crate types currently cannot export any items other than functions tagged with `#[proc_macro]`, `#[proc_macro_derive]`, or `#[proc_macro_attribute]`
-  --> tests/ui/implicit_hasher.rs:92:1
+error: parameter of type `HashSet` should be generalized over different hashers
+  --> tests/ui/implicit_hasher.rs:70:22
+   |
+LL | pub fn set(set: &mut HashSet<i32>) {}
+   |                      ^^^^^^^^^^^^
    |
-LL | pub mod test_macro;
-   | ^^^^^^^^^^^^^^^^^^^
+help: add a type parameter for `BuildHasher`
+   |
+LL | pub fn set<S: ::std::hash::BuildHasher>(set: &mut HashSet<i32, S>) {}
+   |           +++++++++++++++++++++++++++++           ~~~~~~~~~~~~~~~
 
-error: `proc-macro` crate types currently cannot export any items other than functions tagged with `#[proc_macro]`, `#[proc_macro_derive]`, or `#[proc_macro_attribute]`
-  --> tests/ui/implicit_hasher.rs:96:1
+error: impl for `HashMap` should be generalized over different hashers
+  --> tests/ui/implicit_hasher.rs:76:43
+   |
+LL |         impl<K: Hash + Eq, V> Foo<u8> for HashMap<K, V> {
+   |                                           ^^^^^^^^^^^^^
    |
-LL | external! {
-   | ^^^^^^^^^
+   = note: this error originates in the macro `__inline_mac_mod_gen` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: add a type parameter for `BuildHasher`
+   |
+LL ~         impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<u8> for HashMap<K, V, S> {
+LL |             fn make() -> (Self, Self) {
+LL ~                 (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default()))
    |
-   = note: this error originates in the macro `external` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: `proc-macro` crate types currently cannot export any items other than functions tagged with `#[proc_macro]`, `#[proc_macro_derive]`, or `#[proc_macro_attribute]`
-  --> tests/ui/implicit_hasher.rs:101:1
+error: parameter of type `HashMap` should be generalized over different hashers
+  --> tests/ui/implicit_hasher.rs:100:35
    |
 LL | pub async fn election_vote(_data: HashMap<i32, i32>) {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                   ^^^^^^^^^^^^^^^^^
+   |
+help: add a type parameter for `BuildHasher`
+   |
+LL | pub async fn election_vote<S: ::std::hash::BuildHasher>(_data: HashMap<i32, i32, S>) {}
+   |                           +++++++++++++++++++++++++++++        ~~~~~~~~~~~~~~~~~~~~
 
-error: aborting due to 6 previous errors
+error: aborting due to 9 previous errors
 
diff --git a/src/tools/clippy/tests/ui/implicit_return.stderr b/src/tools/clippy/tests/ui/implicit_return.stderr
index f06d4e983c5..3b06f26f5a0 100644
--- a/src/tools/clippy/tests/ui/implicit_return.stderr
+++ b/src/tools/clippy/tests/ui/implicit_return.stderr
@@ -2,88 +2,157 @@ error: missing `return` statement
   --> tests/ui/implicit_return.rs:15:5
    |
 LL |     true
-   |     ^^^^ help: add `return` as shown: `return true`
+   |     ^^^^
    |
    = note: `-D clippy::implicit-return` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::implicit_return)]`
+help: add `return` as shown
+   |
+LL |     return true
+   |
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:19:15
    |
 LL |     if true { true } else { false }
-   |               ^^^^ help: add `return` as shown: `return true`
+   |               ^^^^
+   |
+help: add `return` as shown
+   |
+LL |     if true { return true } else { false }
+   |               ~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:19:29
    |
 LL |     if true { true } else { false }
-   |                             ^^^^^ help: add `return` as shown: `return false`
+   |                             ^^^^^
+   |
+help: add `return` as shown
+   |
+LL |     if true { true } else { return false }
+   |                             ~~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:25:17
    |
 LL |         true => false,
-   |                 ^^^^^ help: add `return` as shown: `return false`
+   |                 ^^^^^
+   |
+help: add `return` as shown
+   |
+LL |         true => return false,
+   |                 ~~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:26:20
    |
 LL |         false => { true },
-   |                    ^^^^ help: add `return` as shown: `return true`
+   |                    ^^^^
+   |
+help: add `return` as shown
+   |
+LL |         false => { return true },
+   |                    ~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:39:9
    |
 LL |         break true;
-   |         ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
+   |         ^^^^^^^^^^
+   |
+help: change `break` to `return` as shown
+   |
+LL |         return true;
+   |         ~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:46:13
    |
 LL |             break true;
-   |             ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
+   |             ^^^^^^^^^^
+   |
+help: change `break` to `return` as shown
+   |
+LL |             return true;
+   |             ~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:54:13
    |
 LL |             break true;
-   |             ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
+   |             ^^^^^^^^^^
+   |
+help: change `break` to `return` as shown
+   |
+LL |             return true;
+   |             ~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:72:18
    |
 LL |     let _ = || { true };
-   |                  ^^^^ help: add `return` as shown: `return true`
+   |                  ^^^^
+   |
+help: add `return` as shown
+   |
+LL |     let _ = || { return true };
+   |                  ~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:73:16
    |
 LL |     let _ = || true;
-   |                ^^^^ help: add `return` as shown: `return true`
+   |                ^^^^
+   |
+help: add `return` as shown
+   |
+LL |     let _ = || return true;
+   |                ~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:81:5
    |
 LL |     format!("test {}", "test")
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `return` as shown: `return format!("test {}", "test")`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: add `return` as shown
+   |
+LL |     return format!("test {}", "test")
+   |
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:90:5
    |
 LL |     m!(true, false)
-   |     ^^^^^^^^^^^^^^^ help: add `return` as shown: `return m!(true, false)`
+   |     ^^^^^^^^^^^^^^^
+   |
+help: add `return` as shown
+   |
+LL |     return m!(true, false)
+   |
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:96:13
    |
 LL |             break true;
-   |             ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
+   |             ^^^^^^^^^^
+   |
+help: change `break` to `return` as shown
+   |
+LL |             return true;
+   |             ~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:101:17
    |
 LL |                 break 'outer false;
-   |                 ^^^^^^^^^^^^^^^^^^ help: change `break` to `return` as shown: `return false`
+   |                 ^^^^^^^^^^^^^^^^^^
+   |
+help: change `break` to `return` as shown
+   |
+LL |                 return false;
+   |                 ~~~~~~~~~~~~
 
 error: missing `return` statement
   --> tests/ui/implicit_return.rs:116:5
@@ -104,7 +173,12 @@ error: missing `return` statement
   --> tests/ui/implicit_return.rs:130:5
    |
 LL |     true
-   |     ^^^^ help: add `return` as shown: `return true`
+   |     ^^^^
+   |
+help: add `return` as shown
+   |
+LL |     return true
+   |
 
 error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui/lossy_float_literal.stderr b/src/tools/clippy/tests/ui/lossy_float_literal.stderr
index b5a07418734..3026854e317 100644
--- a/src/tools/clippy/tests/ui/lossy_float_literal.stderr
+++ b/src/tools/clippy/tests/ui/lossy_float_literal.stderr
@@ -2,70 +2,124 @@ error: literal cannot be represented as the underlying type without loss of prec
   --> 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`
+   |                  ^^^^^^^^^^^^
    |
    = note: `-D clippy::lossy-float-literal` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::lossy_float_literal)]`
+help: consider changing the type or replacing it with
+   |
+LL |     let _: f32 = 16_777_216.0;
+   |                  ~~~~~~~~~~~~
 
 error: literal cannot be represented as the underlying type without loss of precision
   --> 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`
+   |                  ^^^^^^^^^^^^
+   |
+help: consider changing the type or replacing it with
+   |
+LL |     let _: f32 = 16_777_220.0;
+   |                  ~~~~~~~~~~~~
 
 error: literal cannot be represented as the underlying type without loss of precision
   --> 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`
+   |                  ^^^^^^^^^^^
+   |
+help: consider changing the type or replacing it with
+   |
+LL |     let _: f32 = 16_777_220.0;
+   |                  ~~~~~~~~~~~~
 
 error: literal cannot be represented as the underlying type without loss of precision
   --> 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`
+   |                  ^^^^^^^^^^^^^^
+   |
+help: consider changing the type or replacing it with
+   |
+LL |     let _: f32 = 16_777_220.0;
+   |                  ~~~~~~~~~~~~
 
 error: literal cannot be represented as the underlying type without loss of precision
   --> 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`
+   |             ^^^^^^^^^^^^^
+   |
+help: consider changing the type or replacing it with
+   |
+LL |     let _ = 16_777_220_f32;
+   |             ~~~~~~~~~~~~~~
 
 error: literal cannot be represented as the underlying type without loss of precision
   --> 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`
+   |                   ^^^^^^^^^^^^
+   |
+help: consider changing the type or replacing it with
+   |
+LL |     let _: f32 = -16_777_220.0;
+   |                   ~~~~~~~~~~~~
 
 error: literal cannot be represented as the underlying type without loss of precision
   --> 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`
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or replacing it with
+   |
+LL |     let _: f64 = 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: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`
+   |                  ^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or replacing it with
+   |
+LL |     let _: f64 = 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: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`
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or replacing it with
+   |
+LL |     let _: f64 = 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: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`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or replacing it with
+   |
+LL |     let _ = 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: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`
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the type or replacing it with
+   |
+LL |     let _: f64 = -9_007_199_254_740_992.0;
+   |                   ~~~~~~~~~~~~~~~~~~~~~~~
 
 error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/missing_trait_methods.rs b/src/tools/clippy/tests/ui/missing_trait_methods.rs
index 1b09b717ff7..55b904bde59 100644
--- a/src/tools/clippy/tests/ui/missing_trait_methods.rs
+++ b/src/tools/clippy/tests/ui/missing_trait_methods.rs
@@ -49,4 +49,12 @@ impl B for Complete {
     }
 }
 
+trait MissingMultiple {
+    fn one() {}
+    fn two() {}
+    fn three() {}
+}
+
+impl MissingMultiple for Partial {}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/missing_trait_methods.stderr b/src/tools/clippy/tests/ui/missing_trait_methods.stderr
index f5d5d4418b2..9c4968b022d 100644
--- a/src/tools/clippy/tests/ui/missing_trait_methods.stderr
+++ b/src/tools/clippy/tests/ui/missing_trait_methods.stderr
@@ -24,5 +24,41 @@ help: implement the method
 LL |     fn b<'a, T: AsRef<[u8]>>(a: &'a T) -> &'a [u8] {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: missing trait method provided by default: `one`
+  --> tests/ui/missing_trait_methods.rs:58:1
+   |
+LL | impl MissingMultiple for Partial {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: implement the method
+  --> tests/ui/missing_trait_methods.rs:53:5
+   |
+LL |     fn one() {}
+   |     ^^^^^^^^
+
+error: missing trait method provided by default: `two`
+  --> tests/ui/missing_trait_methods.rs:58:1
+   |
+LL | impl MissingMultiple for Partial {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: implement the method
+  --> tests/ui/missing_trait_methods.rs:54:5
+   |
+LL |     fn two() {}
+   |     ^^^^^^^^
+
+error: missing trait method provided by default: `three`
+  --> tests/ui/missing_trait_methods.rs:58:1
+   |
+LL | impl MissingMultiple for Partial {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: implement the method
+  --> tests/ui/missing_trait_methods.rs:55:5
+   |
+LL |     fn three() {}
+   |     ^^^^^^^^^^
+
+error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.fixed b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.fixed
index 5478372cbe0..c1dc8b5e8d0 100644
--- a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.fixed
+++ b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.fixed
@@ -333,4 +333,12 @@ fn main() {
         f(&y); // Don't lint
         f("".to_owned()); // Lint
     }
+    {
+        fn takes_writer<T: std::io::Write>(_: T) {}
+
+        fn issue_12856(mut buffer: &mut Vec<u8>) {
+            takes_writer(&mut buffer); // Don't lint, would make buffer unavailable later
+            buffer.extend(b"\n");
+        }
+    }
 }
diff --git a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.rs b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.rs
index 2643815d939..c7f66824d58 100644
--- a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.rs
+++ b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.rs
@@ -333,4 +333,12 @@ fn main() {
         f(&y); // Don't lint
         f(&"".to_owned()); // Lint
     }
+    {
+        fn takes_writer<T: std::io::Write>(_: T) {}
+
+        fn issue_12856(mut buffer: &mut Vec<u8>) {
+            takes_writer(&mut buffer); // Don't lint, would make buffer unavailable later
+            buffer.extend(b"\n");
+        }
+    }
 }
diff --git a/src/tools/clippy/tests/ui/needless_pub_self.stderr b/src/tools/clippy/tests/ui/needless_pub_self.stderr
index 0bff2e4b8b7..1fdd8416565 100644
--- a/src/tools/clippy/tests/ui/needless_pub_self.stderr
+++ b/src/tools/clippy/tests/ui/needless_pub_self.stderr
@@ -2,22 +2,27 @@ error: unnecessary `pub(self)`
   --> tests/ui/needless_pub_self.rs:13:1
    |
 LL | pub(self) fn a() {}
-   | ^^^^^^^^^ help: remove it
+   | ^^^^^^^^^
    |
    = note: `-D clippy::needless-pub-self` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::needless_pub_self)]`
+   = help: remove it
 
 error: unnecessary `pub(in self)`
   --> tests/ui/needless_pub_self.rs:14:1
    |
 LL | pub(in self) fn b() {}
-   | ^^^^^^^^^^^^ help: remove it
+   | ^^^^^^^^^^^^
+   |
+   = help: remove it
 
 error: unnecessary `pub(self)`
   --> tests/ui/needless_pub_self.rs:20:5
    |
 LL |     pub(self) fn f() {}
-   |     ^^^^^^^^^ help: remove it
+   |     ^^^^^^^^^
+   |
+   = help: remove it
 
 error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui/nonminimal_bool.rs b/src/tools/clippy/tests/ui/nonminimal_bool.rs
index d117e8bf9c7..52b0155a762 100644
--- a/src/tools/clippy/tests/ui/nonminimal_bool.rs
+++ b/src/tools/clippy/tests/ui/nonminimal_bool.rs
@@ -177,3 +177,9 @@ fn issue_12371(x: usize) -> bool {
     // Should not warn!
     !x != 0
 }
+
+// Not linted because it is slow to do so
+// https://github.com/rust-lang/rust-clippy/issues/13206
+fn many_ops(a: bool, b: bool, c: bool, d: bool, e: bool, f: bool) -> bool {
+    (a && c && f) || (!a && b && !d) || (!b && !c && !e) || (d && e && !f)
+}
diff --git a/src/tools/clippy/tests/ui/patterns.fixed b/src/tools/clippy/tests/ui/patterns.fixed
index 332cba97155..feaec33ac15 100644
--- a/src/tools/clippy/tests/ui/patterns.fixed
+++ b/src/tools/clippy/tests/ui/patterns.fixed
@@ -1,7 +1,7 @@
 //@aux-build:proc_macros.rs
 #![warn(clippy::all)]
 #![allow(unused)]
-#![allow(clippy::uninlined_format_args)]
+#![allow(clippy::uninlined_format_args, clippy::single_match)]
 
 #[macro_use]
 extern crate proc_macros;
diff --git a/src/tools/clippy/tests/ui/patterns.rs b/src/tools/clippy/tests/ui/patterns.rs
index 45d907688e3..53812c7deec 100644
--- a/src/tools/clippy/tests/ui/patterns.rs
+++ b/src/tools/clippy/tests/ui/patterns.rs
@@ -1,7 +1,7 @@
 //@aux-build:proc_macros.rs
 #![warn(clippy::all)]
 #![allow(unused)]
-#![allow(clippy::uninlined_format_args)]
+#![allow(clippy::uninlined_format_args, clippy::single_match)]
 
 #[macro_use]
 extern crate proc_macros;
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index d70c9f8d06c..b810fd8224f 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -13,7 +13,10 @@
 #![allow(clippy::disallowed_methods)]
 #![allow(clippy::disallowed_types)]
 #![allow(clippy::mixed_read_write_in_expression)]
+#![allow(clippy::manual_find_map)]
+#![allow(clippy::manual_filter_map)]
 #![allow(clippy::useless_conversion)]
+#![allow(clippy::redundant_pattern_matching)]
 #![allow(clippy::match_result_ok)]
 #![allow(clippy::non_canonical_clone_impl)]
 #![allow(clippy::non_canonical_partial_ord_impl)]
@@ -47,6 +50,7 @@
 #![allow(invalid_value)]
 #![allow(invalid_from_utf8_unchecked)]
 #![allow(let_underscore_drop)]
+#![allow(unexpected_cfgs)]
 #![allow(enum_intrinsics_non_enums)]
 #![allow(non_fmt_panics)]
 #![allow(named_arguments_used_positionally)]
@@ -55,65 +59,72 @@
 #![allow(unknown_lints)]
 #![allow(unused_labels)]
 #![allow(ambiguous_wide_pointer_comparisons)]
-#![warn(clippy::almost_complete_range)]
-#![warn(clippy::disallowed_names)]
-#![warn(clippy::blocks_in_conditions)]
-#![warn(clippy::blocks_in_conditions)]
-#![warn(clippy::blocks_in_conditions)]
-#![warn(clippy::box_collection)]
-#![warn(clippy::redundant_static_lifetimes)]
-#![warn(clippy::cognitive_complexity)]
-#![warn(clippy::derived_hash_with_manual_eq)]
-#![warn(clippy::disallowed_methods)]
-#![warn(clippy::disallowed_types)]
-#![warn(clippy::mixed_read_write_in_expression)]
-#![warn(clippy::useless_conversion)]
-#![warn(clippy::match_result_ok)]
-#![warn(clippy::non_canonical_clone_impl)]
-#![warn(clippy::non_canonical_partial_ord_impl)]
-#![warn(clippy::arithmetic_side_effects)]
-#![warn(clippy::overly_complex_bool_expr)]
-#![warn(clippy::new_without_default)]
-#![warn(clippy::bind_instead_of_map)]
-#![warn(clippy::expect_used)]
-#![warn(clippy::map_unwrap_or)]
-#![warn(clippy::map_unwrap_or)]
-#![warn(clippy::unwrap_used)]
-#![warn(clippy::panicking_overflow_checks)]
-#![warn(clippy::needless_borrow)]
-#![warn(clippy::expect_used)]
-#![warn(clippy::map_unwrap_or)]
-#![warn(clippy::unwrap_used)]
-#![warn(clippy::single_char_add_str)]
-#![warn(clippy::module_name_repetitions)]
-#![warn(clippy::missing_const_for_thread_local)]
-#![warn(clippy::recursive_format_impl)]
-#![warn(clippy::unwrap_or_default)]
-#![warn(clippy::invisible_characters)]
-#![warn(invalid_reference_casting)]
-#![warn(suspicious_double_ref_op)]
-#![warn(invalid_nan_comparisons)]
-#![warn(drop_bounds)]
-#![warn(dropping_copy_types)]
-#![warn(dropping_references)]
-#![warn(useless_ptr_null_checks)]
-#![warn(for_loops_over_fallibles)]
-#![warn(for_loops_over_fallibles)]
-#![warn(for_loops_over_fallibles)]
-#![warn(forgetting_copy_types)]
-#![warn(forgetting_references)]
-#![warn(array_into_iter)]
-#![warn(invalid_atomic_ordering)]
-#![warn(invalid_value)]
-#![warn(invalid_from_utf8_unchecked)]
-#![warn(let_underscore_drop)]
-#![warn(enum_intrinsics_non_enums)]
-#![warn(non_fmt_panics)]
-#![warn(named_arguments_used_positionally)]
-#![warn(temporary_cstring_as_ptr)]
-#![warn(undropped_manually_drops)]
-#![warn(unknown_lints)]
-#![warn(unused_labels)]
-#![warn(ambiguous_wide_pointer_comparisons)]
+#![allow(clippy::reversed_empty_ranges)]
+#![warn(clippy::almost_complete_range)] //~ ERROR: lint `clippy::almost_complete_letter_range`
+#![warn(clippy::disallowed_names)] //~ ERROR: lint `clippy::blacklisted_name`
+#![warn(clippy::blocks_in_conditions)] //~ ERROR: lint `clippy::block_in_if_condition_expr`
+#![warn(clippy::blocks_in_conditions)] //~ ERROR: lint `clippy::block_in_if_condition_stmt`
+#![warn(clippy::blocks_in_conditions)] //~ ERROR: lint `clippy::blocks_in_if_conditions`
+#![warn(clippy::box_collection)] //~ ERROR: lint `clippy::box_vec`
+#![warn(clippy::redundant_static_lifetimes)] //~ ERROR: lint `clippy::const_static_lifetime`
+#![warn(clippy::cognitive_complexity)] //~ ERROR: lint `clippy::cyclomatic_complexity`
+#![warn(clippy::derived_hash_with_manual_eq)] //~ ERROR: lint `clippy::derive_hash_xor_eq`
+#![warn(clippy::disallowed_methods)] //~ ERROR: lint `clippy::disallowed_method`
+#![warn(clippy::disallowed_types)] //~ ERROR: lint `clippy::disallowed_type`
+#![warn(clippy::mixed_read_write_in_expression)] //~ ERROR: lint `clippy::eval_order_dependence`
+#![warn(clippy::manual_find_map)] //~ ERROR: lint `clippy::find_map`
+#![warn(clippy::manual_filter_map)] //~ ERROR: lint `clippy::filter_map`
+#![warn(clippy::useless_conversion)] //~ ERROR: lint `clippy::identity_conversion`
+#![warn(clippy::redundant_pattern_matching)] //~ ERROR: lint `clippy::if_let_redundant_pattern_matching`
+#![warn(clippy::match_result_ok)] //~ ERROR: lint `clippy::if_let_some_result`
+#![warn(clippy::non_canonical_clone_impl)] //~ ERROR: lint `clippy::incorrect_clone_impl_on_copy_type`
+#![warn(clippy::non_canonical_partial_ord_impl)] //~ ERROR: lint `clippy::incorrect_partial_ord_impl_on_ord_type`
+#![warn(clippy::arithmetic_side_effects)] //~ ERROR: lint `clippy::integer_arithmetic`
+#![warn(clippy::overly_complex_bool_expr)] //~ ERROR: lint `clippy::logic_bug`
+#![warn(clippy::new_without_default)] //~ ERROR: lint `clippy::new_without_default_derive`
+#![warn(clippy::bind_instead_of_map)] //~ ERROR: lint `clippy::option_and_then_some`
+#![warn(clippy::expect_used)] //~ ERROR: lint `clippy::option_expect_used`
+#![warn(clippy::map_unwrap_or)] //~ ERROR: lint `clippy::option_map_unwrap_or`
+#![warn(clippy::map_unwrap_or)] //~ ERROR: lint `clippy::option_map_unwrap_or_else`
+#![warn(clippy::unwrap_used)] //~ ERROR: lint `clippy::option_unwrap_used`
+#![warn(clippy::panicking_overflow_checks)] //~ ERROR: lint `clippy::overflow_check_conditional`
+#![warn(clippy::needless_borrow)] //~ ERROR: lint `clippy::ref_in_deref`
+#![warn(clippy::expect_used)] //~ ERROR: lint `clippy::result_expect_used`
+#![warn(clippy::map_unwrap_or)] //~ ERROR: lint `clippy::result_map_unwrap_or_else`
+#![warn(clippy::unwrap_used)] //~ ERROR: lint `clippy::result_unwrap_used`
+#![warn(clippy::single_char_add_str)] //~ ERROR: lint `clippy::single_char_push_str`
+#![warn(clippy::module_name_repetitions)] //~ ERROR: lint `clippy::stutter`
+#![warn(clippy::missing_const_for_thread_local)] //~ ERROR: lint `clippy::thread_local_initializer_can_be_made_const`
+#![warn(clippy::recursive_format_impl)] //~ ERROR: lint `clippy::to_string_in_display`
+#![warn(clippy::unwrap_or_default)] //~ ERROR: lint `clippy::unwrap_or_else_default`
+#![warn(clippy::invisible_characters)] //~ ERROR: lint `clippy::zero_width_space`
+#![warn(invalid_reference_casting)] //~ ERROR: lint `clippy::cast_ref_to_mut`
+#![warn(suspicious_double_ref_op)] //~ ERROR: lint `clippy::clone_double_ref`
+#![warn(invalid_nan_comparisons)] //~ ERROR: lint `clippy::cmp_nan`
+#![warn(drop_bounds)] //~ ERROR: lint `clippy::drop_bounds`
+#![warn(dropping_copy_types)] //~ ERROR: lint `clippy::drop_copy`
+#![warn(dropping_references)] //~ ERROR: lint `clippy::drop_ref`
+#![warn(useless_ptr_null_checks)] //~ ERROR: lint `clippy::fn_null_check`
+#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loop_over_option`
+#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loop_over_result`
+#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loops_over_fallibles`
+#![warn(forgetting_copy_types)] //~ ERROR: lint `clippy::forget_copy`
+#![warn(forgetting_references)] //~ ERROR: lint `clippy::forget_ref`
+#![warn(array_into_iter)] //~ ERROR: lint `clippy::into_iter_on_array`
+#![warn(invalid_atomic_ordering)] //~ ERROR: lint `clippy::invalid_atomic_ordering`
+#![warn(invalid_value)] //~ ERROR: lint `clippy::invalid_ref`
+#![warn(invalid_from_utf8_unchecked)] //~ ERROR: lint `clippy::invalid_utf8_in_unchecked`
+#![warn(let_underscore_drop)] //~ ERROR: lint `clippy::let_underscore_drop`
+#![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::maybe_misused_cfg`
+#![warn(enum_intrinsics_non_enums)] //~ ERROR: lint `clippy::mem_discriminant_non_enum`
+#![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::mismatched_target_os`
+#![warn(non_fmt_panics)] //~ ERROR: lint `clippy::panic_params`
+#![warn(named_arguments_used_positionally)] //~ ERROR: lint `clippy::positional_named_format_parameters`
+#![warn(temporary_cstring_as_ptr)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr`
+#![warn(undropped_manually_drops)] //~ ERROR: lint `clippy::undropped_manually_drops`
+#![warn(unknown_lints)] //~ ERROR: lint `clippy::unknown_clippy_lints`
+#![warn(unused_labels)] //~ ERROR: lint `clippy::unused_label`
+#![warn(ambiguous_wide_pointer_comparisons)] //~ ERROR: lint `clippy::vtable_address_comparisons`
+#![warn(clippy::reversed_empty_ranges)] //~ ERROR: lint `clippy::reverse_range_loop`
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
index 8d0ac3c8f95..e03df1658ee 100644
--- a/src/tools/clippy/tests/ui/rename.rs
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -13,7 +13,10 @@
 #![allow(clippy::disallowed_methods)]
 #![allow(clippy::disallowed_types)]
 #![allow(clippy::mixed_read_write_in_expression)]
+#![allow(clippy::manual_find_map)]
+#![allow(clippy::manual_filter_map)]
 #![allow(clippy::useless_conversion)]
+#![allow(clippy::redundant_pattern_matching)]
 #![allow(clippy::match_result_ok)]
 #![allow(clippy::non_canonical_clone_impl)]
 #![allow(clippy::non_canonical_partial_ord_impl)]
@@ -47,6 +50,7 @@
 #![allow(invalid_value)]
 #![allow(invalid_from_utf8_unchecked)]
 #![allow(let_underscore_drop)]
+#![allow(unexpected_cfgs)]
 #![allow(enum_intrinsics_non_enums)]
 #![allow(non_fmt_panics)]
 #![allow(named_arguments_used_positionally)]
@@ -55,65 +59,72 @@
 #![allow(unknown_lints)]
 #![allow(unused_labels)]
 #![allow(ambiguous_wide_pointer_comparisons)]
-#![warn(clippy::almost_complete_letter_range)]
-#![warn(clippy::blacklisted_name)]
-#![warn(clippy::block_in_if_condition_expr)]
-#![warn(clippy::block_in_if_condition_stmt)]
-#![warn(clippy::blocks_in_if_conditions)]
-#![warn(clippy::box_vec)]
-#![warn(clippy::const_static_lifetime)]
-#![warn(clippy::cyclomatic_complexity)]
-#![warn(clippy::derive_hash_xor_eq)]
-#![warn(clippy::disallowed_method)]
-#![warn(clippy::disallowed_type)]
-#![warn(clippy::eval_order_dependence)]
-#![warn(clippy::identity_conversion)]
-#![warn(clippy::if_let_some_result)]
-#![warn(clippy::incorrect_clone_impl_on_copy_type)]
-#![warn(clippy::incorrect_partial_ord_impl_on_ord_type)]
-#![warn(clippy::integer_arithmetic)]
-#![warn(clippy::logic_bug)]
-#![warn(clippy::new_without_default_derive)]
-#![warn(clippy::option_and_then_some)]
-#![warn(clippy::option_expect_used)]
-#![warn(clippy::option_map_unwrap_or)]
-#![warn(clippy::option_map_unwrap_or_else)]
-#![warn(clippy::option_unwrap_used)]
-#![warn(clippy::overflow_check_conditional)]
-#![warn(clippy::ref_in_deref)]
-#![warn(clippy::result_expect_used)]
-#![warn(clippy::result_map_unwrap_or_else)]
-#![warn(clippy::result_unwrap_used)]
-#![warn(clippy::single_char_push_str)]
-#![warn(clippy::stutter)]
-#![warn(clippy::thread_local_initializer_can_be_made_const)]
-#![warn(clippy::to_string_in_display)]
-#![warn(clippy::unwrap_or_else_default)]
-#![warn(clippy::zero_width_space)]
-#![warn(clippy::cast_ref_to_mut)]
-#![warn(clippy::clone_double_ref)]
-#![warn(clippy::cmp_nan)]
-#![warn(clippy::drop_bounds)]
-#![warn(clippy::drop_copy)]
-#![warn(clippy::drop_ref)]
-#![warn(clippy::fn_null_check)]
-#![warn(clippy::for_loop_over_option)]
-#![warn(clippy::for_loop_over_result)]
-#![warn(clippy::for_loops_over_fallibles)]
-#![warn(clippy::forget_copy)]
-#![warn(clippy::forget_ref)]
-#![warn(clippy::into_iter_on_array)]
-#![warn(clippy::invalid_atomic_ordering)]
-#![warn(clippy::invalid_ref)]
-#![warn(clippy::invalid_utf8_in_unchecked)]
-#![warn(clippy::let_underscore_drop)]
-#![warn(clippy::mem_discriminant_non_enum)]
-#![warn(clippy::panic_params)]
-#![warn(clippy::positional_named_format_parameters)]
-#![warn(clippy::temporary_cstring_as_ptr)]
-#![warn(clippy::undropped_manually_drops)]
-#![warn(clippy::unknown_clippy_lints)]
-#![warn(clippy::unused_label)]
-#![warn(clippy::vtable_address_comparisons)]
+#![allow(clippy::reversed_empty_ranges)]
+#![warn(clippy::almost_complete_letter_range)] //~ ERROR: lint `clippy::almost_complete_letter_range`
+#![warn(clippy::blacklisted_name)] //~ ERROR: lint `clippy::blacklisted_name`
+#![warn(clippy::block_in_if_condition_expr)] //~ ERROR: lint `clippy::block_in_if_condition_expr`
+#![warn(clippy::block_in_if_condition_stmt)] //~ ERROR: lint `clippy::block_in_if_condition_stmt`
+#![warn(clippy::blocks_in_if_conditions)] //~ ERROR: lint `clippy::blocks_in_if_conditions`
+#![warn(clippy::box_vec)] //~ ERROR: lint `clippy::box_vec`
+#![warn(clippy::const_static_lifetime)] //~ ERROR: lint `clippy::const_static_lifetime`
+#![warn(clippy::cyclomatic_complexity)] //~ ERROR: lint `clippy::cyclomatic_complexity`
+#![warn(clippy::derive_hash_xor_eq)] //~ ERROR: lint `clippy::derive_hash_xor_eq`
+#![warn(clippy::disallowed_method)] //~ ERROR: lint `clippy::disallowed_method`
+#![warn(clippy::disallowed_type)] //~ ERROR: lint `clippy::disallowed_type`
+#![warn(clippy::eval_order_dependence)] //~ ERROR: lint `clippy::eval_order_dependence`
+#![warn(clippy::find_map)] //~ ERROR: lint `clippy::find_map`
+#![warn(clippy::filter_map)] //~ ERROR: lint `clippy::filter_map`
+#![warn(clippy::identity_conversion)] //~ ERROR: lint `clippy::identity_conversion`
+#![warn(clippy::if_let_redundant_pattern_matching)] //~ ERROR: lint `clippy::if_let_redundant_pattern_matching`
+#![warn(clippy::if_let_some_result)] //~ ERROR: lint `clippy::if_let_some_result`
+#![warn(clippy::incorrect_clone_impl_on_copy_type)] //~ ERROR: lint `clippy::incorrect_clone_impl_on_copy_type`
+#![warn(clippy::incorrect_partial_ord_impl_on_ord_type)] //~ ERROR: lint `clippy::incorrect_partial_ord_impl_on_ord_type`
+#![warn(clippy::integer_arithmetic)] //~ ERROR: lint `clippy::integer_arithmetic`
+#![warn(clippy::logic_bug)] //~ ERROR: lint `clippy::logic_bug`
+#![warn(clippy::new_without_default_derive)] //~ ERROR: lint `clippy::new_without_default_derive`
+#![warn(clippy::option_and_then_some)] //~ ERROR: lint `clippy::option_and_then_some`
+#![warn(clippy::option_expect_used)] //~ ERROR: lint `clippy::option_expect_used`
+#![warn(clippy::option_map_unwrap_or)] //~ ERROR: lint `clippy::option_map_unwrap_or`
+#![warn(clippy::option_map_unwrap_or_else)] //~ ERROR: lint `clippy::option_map_unwrap_or_else`
+#![warn(clippy::option_unwrap_used)] //~ ERROR: lint `clippy::option_unwrap_used`
+#![warn(clippy::overflow_check_conditional)] //~ ERROR: lint `clippy::overflow_check_conditional`
+#![warn(clippy::ref_in_deref)] //~ ERROR: lint `clippy::ref_in_deref`
+#![warn(clippy::result_expect_used)] //~ ERROR: lint `clippy::result_expect_used`
+#![warn(clippy::result_map_unwrap_or_else)] //~ ERROR: lint `clippy::result_map_unwrap_or_else`
+#![warn(clippy::result_unwrap_used)] //~ ERROR: lint `clippy::result_unwrap_used`
+#![warn(clippy::single_char_push_str)] //~ ERROR: lint `clippy::single_char_push_str`
+#![warn(clippy::stutter)] //~ ERROR: lint `clippy::stutter`
+#![warn(clippy::thread_local_initializer_can_be_made_const)] //~ ERROR: lint `clippy::thread_local_initializer_can_be_made_const`
+#![warn(clippy::to_string_in_display)] //~ ERROR: lint `clippy::to_string_in_display`
+#![warn(clippy::unwrap_or_else_default)] //~ ERROR: lint `clippy::unwrap_or_else_default`
+#![warn(clippy::zero_width_space)] //~ ERROR: lint `clippy::zero_width_space`
+#![warn(clippy::cast_ref_to_mut)] //~ ERROR: lint `clippy::cast_ref_to_mut`
+#![warn(clippy::clone_double_ref)] //~ ERROR: lint `clippy::clone_double_ref`
+#![warn(clippy::cmp_nan)] //~ ERROR: lint `clippy::cmp_nan`
+#![warn(clippy::drop_bounds)] //~ ERROR: lint `clippy::drop_bounds`
+#![warn(clippy::drop_copy)] //~ ERROR: lint `clippy::drop_copy`
+#![warn(clippy::drop_ref)] //~ ERROR: lint `clippy::drop_ref`
+#![warn(clippy::fn_null_check)] //~ ERROR: lint `clippy::fn_null_check`
+#![warn(clippy::for_loop_over_option)] //~ ERROR: lint `clippy::for_loop_over_option`
+#![warn(clippy::for_loop_over_result)] //~ ERROR: lint `clippy::for_loop_over_result`
+#![warn(clippy::for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loops_over_fallibles`
+#![warn(clippy::forget_copy)] //~ ERROR: lint `clippy::forget_copy`
+#![warn(clippy::forget_ref)] //~ ERROR: lint `clippy::forget_ref`
+#![warn(clippy::into_iter_on_array)] //~ ERROR: lint `clippy::into_iter_on_array`
+#![warn(clippy::invalid_atomic_ordering)] //~ ERROR: lint `clippy::invalid_atomic_ordering`
+#![warn(clippy::invalid_ref)] //~ ERROR: lint `clippy::invalid_ref`
+#![warn(clippy::invalid_utf8_in_unchecked)] //~ ERROR: lint `clippy::invalid_utf8_in_unchecked`
+#![warn(clippy::let_underscore_drop)] //~ ERROR: lint `clippy::let_underscore_drop`
+#![warn(clippy::maybe_misused_cfg)] //~ ERROR: lint `clippy::maybe_misused_cfg`
+#![warn(clippy::mem_discriminant_non_enum)] //~ ERROR: lint `clippy::mem_discriminant_non_enum`
+#![warn(clippy::mismatched_target_os)] //~ ERROR: lint `clippy::mismatched_target_os`
+#![warn(clippy::panic_params)] //~ ERROR: lint `clippy::panic_params`
+#![warn(clippy::positional_named_format_parameters)] //~ ERROR: lint `clippy::positional_named_format_parameters`
+#![warn(clippy::temporary_cstring_as_ptr)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr`
+#![warn(clippy::undropped_manually_drops)] //~ ERROR: lint `clippy::undropped_manually_drops`
+#![warn(clippy::unknown_clippy_lints)] //~ ERROR: lint `clippy::unknown_clippy_lints`
+#![warn(clippy::unused_label)] //~ ERROR: lint `clippy::unused_label`
+#![warn(clippy::vtable_address_comparisons)] //~ ERROR: lint `clippy::vtable_address_comparisons`
+#![warn(clippy::reverse_range_loop)] //~ ERROR: lint `clippy::reverse_range_loop`
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index d6637324a03..46d9f0fac59 100644
--- a/src/tools/clippy/tests/ui/rename.stderr
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -1,5 +1,5 @@
 error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
-  --> tests/ui/rename.rs:58:9
+  --> tests/ui/rename.rs:63:9
    |
 LL | #![warn(clippy::almost_complete_letter_range)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
@@ -8,358 +8,394 @@ LL | #![warn(clippy::almost_complete_letter_range)]
    = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]`
 
 error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
-  --> tests/ui/rename.rs:59:9
+  --> tests/ui/rename.rs:64:9
    |
 LL | #![warn(clippy::blacklisted_name)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
 
 error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_conditions`
-  --> tests/ui/rename.rs:60:9
+  --> tests/ui/rename.rs:65:9
    |
 LL | #![warn(clippy::block_in_if_condition_expr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions`
 
 error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_conditions`
-  --> tests/ui/rename.rs:61:9
+  --> tests/ui/rename.rs:66:9
    |
 LL | #![warn(clippy::block_in_if_condition_stmt)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions`
 
 error: lint `clippy::blocks_in_if_conditions` has been renamed to `clippy::blocks_in_conditions`
-  --> tests/ui/rename.rs:62:9
+  --> tests/ui/rename.rs:67:9
    |
 LL | #![warn(clippy::blocks_in_if_conditions)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions`
 
 error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
-  --> tests/ui/rename.rs:63:9
+  --> tests/ui/rename.rs:68:9
    |
 LL | #![warn(clippy::box_vec)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
 
 error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
-  --> tests/ui/rename.rs:64:9
+  --> tests/ui/rename.rs:69:9
    |
 LL | #![warn(clippy::const_static_lifetime)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
 
 error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
-  --> tests/ui/rename.rs:65:9
+  --> tests/ui/rename.rs:70:9
    |
 LL | #![warn(clippy::cyclomatic_complexity)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
 
 error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq`
-  --> tests/ui/rename.rs:66:9
+  --> tests/ui/rename.rs:71:9
    |
 LL | #![warn(clippy::derive_hash_xor_eq)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq`
 
 error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
-  --> tests/ui/rename.rs:67:9
+  --> tests/ui/rename.rs:72:9
    |
 LL | #![warn(clippy::disallowed_method)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
 
 error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
-  --> tests/ui/rename.rs:68:9
+  --> tests/ui/rename.rs:73:9
    |
 LL | #![warn(clippy::disallowed_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
 
 error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
-  --> tests/ui/rename.rs:69:9
+  --> tests/ui/rename.rs:74:9
    |
 LL | #![warn(clippy::eval_order_dependence)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
 
+error: lint `clippy::find_map` has been renamed to `clippy::manual_find_map`
+  --> tests/ui/rename.rs:75:9
+   |
+LL | #![warn(clippy::find_map)]
+   |         ^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_find_map`
+
+error: lint `clippy::filter_map` has been renamed to `clippy::manual_filter_map`
+  --> tests/ui/rename.rs:76:9
+   |
+LL | #![warn(clippy::filter_map)]
+   |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_filter_map`
+
 error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
-  --> tests/ui/rename.rs:70:9
+  --> tests/ui/rename.rs:77:9
    |
 LL | #![warn(clippy::identity_conversion)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
 
+error: lint `clippy::if_let_redundant_pattern_matching` has been renamed to `clippy::redundant_pattern_matching`
+  --> tests/ui/rename.rs:78:9
+   |
+LL | #![warn(clippy::if_let_redundant_pattern_matching)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_pattern_matching`
+
 error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
-  --> tests/ui/rename.rs:71:9
+  --> tests/ui/rename.rs:79:9
    |
 LL | #![warn(clippy::if_let_some_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
 
 error: lint `clippy::incorrect_clone_impl_on_copy_type` has been renamed to `clippy::non_canonical_clone_impl`
-  --> tests/ui/rename.rs:72:9
+  --> tests/ui/rename.rs:80:9
    |
 LL | #![warn(clippy::incorrect_clone_impl_on_copy_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_clone_impl`
 
 error: lint `clippy::incorrect_partial_ord_impl_on_ord_type` has been renamed to `clippy::non_canonical_partial_ord_impl`
-  --> tests/ui/rename.rs:73:9
+  --> tests/ui/rename.rs:81:9
    |
 LL | #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_partial_ord_impl`
 
 error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects`
-  --> tests/ui/rename.rs:74:9
+  --> tests/ui/rename.rs:82:9
    |
 LL | #![warn(clippy::integer_arithmetic)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects`
 
 error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
-  --> tests/ui/rename.rs:75:9
+  --> tests/ui/rename.rs:83:9
    |
 LL | #![warn(clippy::logic_bug)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
 
 error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
-  --> tests/ui/rename.rs:76:9
+  --> tests/ui/rename.rs:84:9
    |
 LL | #![warn(clippy::new_without_default_derive)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
 
 error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
-  --> tests/ui/rename.rs:77:9
+  --> tests/ui/rename.rs:85:9
    |
 LL | #![warn(clippy::option_and_then_some)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
 
 error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
-  --> tests/ui/rename.rs:78:9
+  --> tests/ui/rename.rs:86:9
    |
 LL | #![warn(clippy::option_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
-  --> tests/ui/rename.rs:79:9
+  --> tests/ui/rename.rs:87:9
    |
 LL | #![warn(clippy::option_map_unwrap_or)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> tests/ui/rename.rs:80:9
+  --> tests/ui/rename.rs:88:9
    |
 LL | #![warn(clippy::option_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> tests/ui/rename.rs:81:9
+  --> tests/ui/rename.rs:89:9
    |
 LL | #![warn(clippy::option_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::overflow_check_conditional` has been renamed to `clippy::panicking_overflow_checks`
-  --> tests/ui/rename.rs:82:9
+  --> tests/ui/rename.rs:90:9
    |
 LL | #![warn(clippy::overflow_check_conditional)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::panicking_overflow_checks`
 
 error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
-  --> tests/ui/rename.rs:83:9
+  --> tests/ui/rename.rs:91:9
    |
 LL | #![warn(clippy::ref_in_deref)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
 
 error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
-  --> tests/ui/rename.rs:84:9
+  --> tests/ui/rename.rs:92:9
    |
 LL | #![warn(clippy::result_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> tests/ui/rename.rs:85:9
+  --> tests/ui/rename.rs:93:9
    |
 LL | #![warn(clippy::result_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> tests/ui/rename.rs:86:9
+  --> tests/ui/rename.rs:94:9
    |
 LL | #![warn(clippy::result_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
-  --> tests/ui/rename.rs:87:9
+  --> tests/ui/rename.rs:95:9
    |
 LL | #![warn(clippy::single_char_push_str)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
 
 error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
-  --> tests/ui/rename.rs:88:9
+  --> tests/ui/rename.rs:96:9
    |
 LL | #![warn(clippy::stutter)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
 
 error: lint `clippy::thread_local_initializer_can_be_made_const` has been renamed to `clippy::missing_const_for_thread_local`
-  --> tests/ui/rename.rs:89:9
+  --> tests/ui/rename.rs:97:9
    |
 LL | #![warn(clippy::thread_local_initializer_can_be_made_const)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::missing_const_for_thread_local`
 
 error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
-  --> tests/ui/rename.rs:90:9
+  --> tests/ui/rename.rs:98:9
    |
 LL | #![warn(clippy::to_string_in_display)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
 
 error: lint `clippy::unwrap_or_else_default` has been renamed to `clippy::unwrap_or_default`
-  --> tests/ui/rename.rs:91:9
+  --> tests/ui/rename.rs:99:9
    |
 LL | #![warn(clippy::unwrap_or_else_default)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default`
 
 error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
-  --> tests/ui/rename.rs:92:9
+  --> tests/ui/rename.rs:100:9
    |
 LL | #![warn(clippy::zero_width_space)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
 
 error: lint `clippy::cast_ref_to_mut` has been renamed to `invalid_reference_casting`
-  --> tests/ui/rename.rs:93:9
+  --> tests/ui/rename.rs:101:9
    |
 LL | #![warn(clippy::cast_ref_to_mut)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_reference_casting`
 
 error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op`
-  --> tests/ui/rename.rs:94:9
+  --> tests/ui/rename.rs:102:9
    |
 LL | #![warn(clippy::clone_double_ref)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op`
 
 error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons`
-  --> tests/ui/rename.rs:95:9
+  --> tests/ui/rename.rs:103:9
    |
 LL | #![warn(clippy::cmp_nan)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons`
 
 error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
-  --> tests/ui/rename.rs:96:9
+  --> tests/ui/rename.rs:104:9
    |
 LL | #![warn(clippy::drop_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 
 error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types`
-  --> tests/ui/rename.rs:97:9
+  --> tests/ui/rename.rs:105:9
    |
 LL | #![warn(clippy::drop_copy)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types`
 
 error: lint `clippy::drop_ref` has been renamed to `dropping_references`
-  --> tests/ui/rename.rs:98:9
+  --> tests/ui/rename.rs:106:9
    |
 LL | #![warn(clippy::drop_ref)]
    |         ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references`
 
 error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks`
-  --> tests/ui/rename.rs:99:9
+  --> tests/ui/rename.rs:107:9
    |
 LL | #![warn(clippy::fn_null_check)]
    |         ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks`
 
 error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
-  --> tests/ui/rename.rs:100:9
+  --> tests/ui/rename.rs:108:9
    |
 LL | #![warn(clippy::for_loop_over_option)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
-  --> tests/ui/rename.rs:101:9
+  --> tests/ui/rename.rs:109:9
    |
 LL | #![warn(clippy::for_loop_over_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
-  --> tests/ui/rename.rs:102:9
+  --> tests/ui/rename.rs:110:9
    |
 LL | #![warn(clippy::for_loops_over_fallibles)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types`
-  --> tests/ui/rename.rs:103:9
+  --> tests/ui/rename.rs:111:9
    |
 LL | #![warn(clippy::forget_copy)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types`
 
 error: lint `clippy::forget_ref` has been renamed to `forgetting_references`
-  --> tests/ui/rename.rs:104:9
+  --> tests/ui/rename.rs:112:9
    |
 LL | #![warn(clippy::forget_ref)]
    |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references`
 
 error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-  --> tests/ui/rename.rs:105:9
+  --> tests/ui/rename.rs:113:9
    |
 LL | #![warn(clippy::into_iter_on_array)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
 
 error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
-  --> tests/ui/rename.rs:106:9
+  --> tests/ui/rename.rs:114:9
    |
 LL | #![warn(clippy::invalid_atomic_ordering)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
 
 error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
-  --> tests/ui/rename.rs:107:9
+  --> tests/ui/rename.rs:115:9
    |
 LL | #![warn(clippy::invalid_ref)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
 
 error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked`
-  --> tests/ui/rename.rs:108:9
+  --> tests/ui/rename.rs:116:9
    |
 LL | #![warn(clippy::invalid_utf8_in_unchecked)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked`
 
 error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
-  --> tests/ui/rename.rs:109:9
+  --> tests/ui/rename.rs:117:9
    |
 LL | #![warn(clippy::let_underscore_drop)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
 
+error: lint `clippy::maybe_misused_cfg` has been renamed to `unexpected_cfgs`
+  --> tests/ui/rename.rs:118:9
+   |
+LL | #![warn(clippy::maybe_misused_cfg)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs`
+
 error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
-  --> tests/ui/rename.rs:110:9
+  --> tests/ui/rename.rs:119:9
    |
 LL | #![warn(clippy::mem_discriminant_non_enum)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
 
+error: lint `clippy::mismatched_target_os` has been renamed to `unexpected_cfgs`
+  --> tests/ui/rename.rs:120:9
+   |
+LL | #![warn(clippy::mismatched_target_os)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs`
+
 error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
-  --> tests/ui/rename.rs:111:9
+  --> tests/ui/rename.rs:121:9
    |
 LL | #![warn(clippy::panic_params)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
 
 error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
-  --> tests/ui/rename.rs:112:9
+  --> tests/ui/rename.rs:122:9
    |
 LL | #![warn(clippy::positional_named_format_parameters)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
 
 error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
-  --> tests/ui/rename.rs:113:9
+  --> tests/ui/rename.rs:123:9
    |
 LL | #![warn(clippy::temporary_cstring_as_ptr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
 
 error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops`
-  --> tests/ui/rename.rs:114:9
+  --> tests/ui/rename.rs:124:9
    |
 LL | #![warn(clippy::undropped_manually_drops)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops`
 
 error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
-  --> tests/ui/rename.rs:115:9
+  --> tests/ui/rename.rs:125:9
    |
 LL | #![warn(clippy::unknown_clippy_lints)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
 
 error: lint `clippy::unused_label` has been renamed to `unused_labels`
-  --> tests/ui/rename.rs:116:9
+  --> tests/ui/rename.rs:126:9
    |
 LL | #![warn(clippy::unused_label)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
 
 error: lint `clippy::vtable_address_comparisons` has been renamed to `ambiguous_wide_pointer_comparisons`
-  --> tests/ui/rename.rs:117:9
+  --> tests/ui/rename.rs:127:9
    |
 LL | #![warn(clippy::vtable_address_comparisons)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `ambiguous_wide_pointer_comparisons`
 
-error: aborting due to 60 previous errors
+error: lint `clippy::reverse_range_loop` has been renamed to `clippy::reversed_empty_ranges`
+  --> tests/ui/rename.rs:128:9
+   |
+LL | #![warn(clippy::reverse_range_loop)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges`
+
+error: aborting due to 66 previous errors
 
diff --git a/src/tools/clippy/tests/ui/set_contains_or_insert.rs b/src/tools/clippy/tests/ui/set_contains_or_insert.rs
index 8465007402a..d3a3e1c878b 100644
--- a/src/tools/clippy/tests/ui/set_contains_or_insert.rs
+++ b/src/tools/clippy/tests/ui/set_contains_or_insert.rs
@@ -3,17 +3,78 @@
 #![allow(clippy::needless_borrow)]
 #![warn(clippy::set_contains_or_insert)]
 
-use std::collections::HashSet;
+use std::collections::{BTreeSet, HashSet};
 
-fn main() {
-    should_warn_cases();
+fn should_warn_hashset() {
+    let mut set = HashSet::new();
+    let value = 5;
+
+    if !set.contains(&value) {
+        set.insert(value);
+        println!("Just a comment");
+    }
+
+    if set.contains(&value) {
+        set.insert(value);
+        println!("Just a comment");
+    }
+
+    if !set.contains(&value) {
+        set.insert(value);
+    }
 
-    should_not_warn_cases();
+    if !!set.contains(&value) {
+        set.insert(value);
+        println!("Just a comment");
+    }
+
+    if (&set).contains(&value) {
+        set.insert(value);
+    }
+
+    let borrow_value = &6;
+    if !set.contains(borrow_value) {
+        set.insert(*borrow_value);
+    }
+
+    let borrow_set = &mut set;
+    if !borrow_set.contains(&value) {
+        borrow_set.insert(value);
+    }
 }
 
-fn should_warn_cases() {
+fn should_not_warn_hashset() {
     let mut set = HashSet::new();
     let value = 5;
+    let another_value = 6;
+
+    if !set.contains(&value) {
+        set.insert(another_value);
+    }
+
+    if !set.contains(&value) {
+        println!("Just a comment");
+    }
+
+    if simply_true() {
+        set.insert(value);
+    }
+
+    if !set.contains(&value) {
+        set.replace(value); //it is not insert
+        println!("Just a comment");
+    }
+
+    if set.contains(&value) {
+        println!("value is already in set");
+    } else {
+        set.insert(value);
+    }
+}
+
+fn should_warn_btreeset() {
+    let mut set = BTreeSet::new();
+    let value = 5;
 
     if !set.contains(&value) {
         set.insert(value);
@@ -49,8 +110,8 @@ fn should_warn_cases() {
     }
 }
 
-fn should_not_warn_cases() {
-    let mut set = HashSet::new();
+fn should_not_warn_btreeset() {
+    let mut set = BTreeSet::new();
     let value = 5;
     let another_value = 6;
 
@@ -81,3 +142,11 @@ fn should_not_warn_cases() {
 fn simply_true() -> bool {
     true
 }
+
+// This is placed last in order to be able to add new tests without changing line numbers
+fn main() {
+    should_warn_hashset();
+    should_warn_btreeset();
+    should_not_warn_hashset();
+    should_not_warn_btreeset();
+}
diff --git a/src/tools/clippy/tests/ui/set_contains_or_insert.stderr b/src/tools/clippy/tests/ui/set_contains_or_insert.stderr
index 507e20964fc..14ad6300544 100644
--- a/src/tools/clippy/tests/ui/set_contains_or_insert.stderr
+++ b/src/tools/clippy/tests/ui/set_contains_or_insert.stderr
@@ -1,5 +1,5 @@
 error: usage of `HashSet::insert` after `HashSet::contains`
-  --> tests/ui/set_contains_or_insert.rs:18:13
+  --> tests/ui/set_contains_or_insert.rs:12:13
    |
 LL |     if !set.contains(&value) {
    |             ^^^^^^^^^^^^^^^^
@@ -10,7 +10,7 @@ LL |         set.insert(value);
    = help: to override `-D warnings` add `#[allow(clippy::set_contains_or_insert)]`
 
 error: usage of `HashSet::insert` after `HashSet::contains`
-  --> tests/ui/set_contains_or_insert.rs:23:12
+  --> tests/ui/set_contains_or_insert.rs:17:12
    |
 LL |     if set.contains(&value) {
    |            ^^^^^^^^^^^^^^^^
@@ -18,7 +18,7 @@ LL |         set.insert(value);
    |             ^^^^^^^^^^^^^
 
 error: usage of `HashSet::insert` after `HashSet::contains`
-  --> tests/ui/set_contains_or_insert.rs:28:13
+  --> tests/ui/set_contains_or_insert.rs:22:13
    |
 LL |     if !set.contains(&value) {
    |             ^^^^^^^^^^^^^^^^
@@ -26,7 +26,7 @@ LL |         set.insert(value);
    |             ^^^^^^^^^^^^^
 
 error: usage of `HashSet::insert` after `HashSet::contains`
-  --> tests/ui/set_contains_or_insert.rs:32:14
+  --> tests/ui/set_contains_or_insert.rs:26:14
    |
 LL |     if !!set.contains(&value) {
    |              ^^^^^^^^^^^^^^^^
@@ -34,7 +34,7 @@ LL |         set.insert(value);
    |             ^^^^^^^^^^^^^
 
 error: usage of `HashSet::insert` after `HashSet::contains`
-  --> tests/ui/set_contains_or_insert.rs:37:15
+  --> tests/ui/set_contains_or_insert.rs:31:15
    |
 LL |     if (&set).contains(&value) {
    |               ^^^^^^^^^^^^^^^^
@@ -42,7 +42,7 @@ LL |         set.insert(value);
    |             ^^^^^^^^^^^^^
 
 error: usage of `HashSet::insert` after `HashSet::contains`
-  --> tests/ui/set_contains_or_insert.rs:42:13
+  --> tests/ui/set_contains_or_insert.rs:36:13
    |
 LL |     if !set.contains(borrow_value) {
    |             ^^^^^^^^^^^^^^^^^^^^^^
@@ -50,12 +50,68 @@ LL |         set.insert(*borrow_value);
    |             ^^^^^^^^^^^^^^^^^^^^^
 
 error: usage of `HashSet::insert` after `HashSet::contains`
-  --> tests/ui/set_contains_or_insert.rs:47:20
+  --> tests/ui/set_contains_or_insert.rs:41:20
    |
 LL |     if !borrow_set.contains(&value) {
    |                    ^^^^^^^^^^^^^^^^
 LL |         borrow_set.insert(value);
    |                    ^^^^^^^^^^^^^
 
-error: aborting due to 7 previous errors
+error: usage of `BTreeSet::insert` after `BTreeSet::contains`
+  --> tests/ui/set_contains_or_insert.rs:79:13
+   |
+LL |     if !set.contains(&value) {
+   |             ^^^^^^^^^^^^^^^^
+LL |         set.insert(value);
+   |             ^^^^^^^^^^^^^
+
+error: usage of `BTreeSet::insert` after `BTreeSet::contains`
+  --> tests/ui/set_contains_or_insert.rs:84:12
+   |
+LL |     if set.contains(&value) {
+   |            ^^^^^^^^^^^^^^^^
+LL |         set.insert(value);
+   |             ^^^^^^^^^^^^^
+
+error: usage of `BTreeSet::insert` after `BTreeSet::contains`
+  --> tests/ui/set_contains_or_insert.rs:89:13
+   |
+LL |     if !set.contains(&value) {
+   |             ^^^^^^^^^^^^^^^^
+LL |         set.insert(value);
+   |             ^^^^^^^^^^^^^
+
+error: usage of `BTreeSet::insert` after `BTreeSet::contains`
+  --> tests/ui/set_contains_or_insert.rs:93:14
+   |
+LL |     if !!set.contains(&value) {
+   |              ^^^^^^^^^^^^^^^^
+LL |         set.insert(value);
+   |             ^^^^^^^^^^^^^
+
+error: usage of `BTreeSet::insert` after `BTreeSet::contains`
+  --> tests/ui/set_contains_or_insert.rs:98:15
+   |
+LL |     if (&set).contains(&value) {
+   |               ^^^^^^^^^^^^^^^^
+LL |         set.insert(value);
+   |             ^^^^^^^^^^^^^
+
+error: usage of `BTreeSet::insert` after `BTreeSet::contains`
+  --> tests/ui/set_contains_or_insert.rs:103:13
+   |
+LL |     if !set.contains(borrow_value) {
+   |             ^^^^^^^^^^^^^^^^^^^^^^
+LL |         set.insert(*borrow_value);
+   |             ^^^^^^^^^^^^^^^^^^^^^
+
+error: usage of `BTreeSet::insert` after `BTreeSet::contains`
+  --> tests/ui/set_contains_or_insert.rs:108:20
+   |
+LL |     if !borrow_set.contains(&value) {
+   |                    ^^^^^^^^^^^^^^^^
+LL |         borrow_set.insert(value);
+   |                    ^^^^^^^^^^^^^
+
+error: aborting due to 14 previous errors
 
diff --git a/src/tools/clippy/tests/ui/single_match.fixed b/src/tools/clippy/tests/ui/single_match.fixed
index acd70416d8b..5249c440889 100644
--- a/src/tools/clippy/tests/ui/single_match.fixed
+++ b/src/tools/clippy/tests/ui/single_match.fixed
@@ -253,3 +253,46 @@ mod issue8634 {
         }
     }
 }
+
+fn issue11365() {
+    enum Foo {
+        A,
+        B,
+        C,
+    }
+    use Foo::{A, B, C};
+
+    match Some(A) {
+        Some(A | B | C) => println!(),
+        None => {},
+    }
+
+    match Some(A) {
+        Some(A | B) => println!(),
+        Some { 0: C } | None => {},
+    }
+
+    match [A, A] {
+        [A, _] => println!(),
+        [_, A | B | C] => {},
+    }
+
+    match Ok::<_, u32>(Some(A)) {
+        Ok(Some(A)) => println!(),
+        Err(_) | Ok(None | Some(B | C)) => {},
+    }
+
+    if let Ok(Some(A)) = Ok::<_, u32>(Some(A)) { println!() }
+
+    match &Some(A) {
+        Some(A | B | C) => println!(),
+        None => {},
+    }
+
+    match &Some(A) {
+        &Some(A | B | C) => println!(),
+        None => {},
+    }
+
+    if let Some(A | B) = &Some(A) { println!() }
+}
diff --git a/src/tools/clippy/tests/ui/single_match.rs b/src/tools/clippy/tests/ui/single_match.rs
index bde78199810..882098a56e7 100644
--- a/src/tools/clippy/tests/ui/single_match.rs
+++ b/src/tools/clippy/tests/ui/single_match.rs
@@ -311,3 +311,52 @@ mod issue8634 {
         }
     }
 }
+
+fn issue11365() {
+    enum Foo {
+        A,
+        B,
+        C,
+    }
+    use Foo::{A, B, C};
+
+    match Some(A) {
+        Some(A | B | C) => println!(),
+        None => {},
+    }
+
+    match Some(A) {
+        Some(A | B) => println!(),
+        Some { 0: C } | None => {},
+    }
+
+    match [A, A] {
+        [A, _] => println!(),
+        [_, A | B | C] => {},
+    }
+
+    match Ok::<_, u32>(Some(A)) {
+        Ok(Some(A)) => println!(),
+        Err(_) | Ok(None | Some(B | C)) => {},
+    }
+
+    match Ok::<_, u32>(Some(A)) {
+        Ok(Some(A)) => println!(),
+        Err(_) | Ok(None | Some(_)) => {},
+    }
+
+    match &Some(A) {
+        Some(A | B | C) => println!(),
+        None => {},
+    }
+
+    match &Some(A) {
+        &Some(A | B | C) => println!(),
+        None => {},
+    }
+
+    match &Some(A) {
+        Some(A | B) => println!(),
+        None | Some(_) => {},
+    }
+}
diff --git a/src/tools/clippy/tests/ui/single_match.stderr b/src/tools/clippy/tests/ui/single_match.stderr
index a249c120ee4..ceb2a193bf7 100644
--- a/src/tools/clippy/tests/ui/single_match.stderr
+++ b/src/tools/clippy/tests/ui/single_match.stderr
@@ -198,5 +198,23 @@ LL +         }
 LL +     }
    |
 
-error: aborting due to 18 previous errors
+error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
+  --> tests/ui/single_match.rs:343:5
+   |
+LL | /     match Ok::<_, u32>(Some(A)) {
+LL | |         Ok(Some(A)) => println!(),
+LL | |         Err(_) | Ok(None | Some(_)) => {},
+LL | |     }
+   | |_____^ help: try: `if let Ok(Some(A)) = Ok::<_, u32>(Some(A)) { println!() }`
+
+error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
+  --> tests/ui/single_match.rs:358:5
+   |
+LL | /     match &Some(A) {
+LL | |         Some(A | B) => println!(),
+LL | |         None | Some(_) => {},
+LL | |     }
+   | |_____^ help: try: `if let Some(A | B) = &Some(A) { println!() }`
+
+error: aborting due to 20 previous errors
 
diff --git a/src/tools/clippy/tests/ui/single_match_else.fixed b/src/tools/clippy/tests/ui/single_match_else.fixed
index e840adf0fa3..163be16ad8b 100644
--- a/src/tools/clippy/tests/ui/single_match_else.fixed
+++ b/src/tools/clippy/tests/ui/single_match_else.fixed
@@ -89,7 +89,7 @@ fn main() {
 
     // lint here
     use std::convert::Infallible;
-    if let Ok(a) = Result::<i32, Infallible>::Ok(1) { println!("${:?}", a) } else {
+    if let Ok(a) = Result::<i32, &Infallible>::Ok(1) { println!("${:?}", a) } else {
         println!("else block");
         return;
     }
diff --git a/src/tools/clippy/tests/ui/single_match_else.rs b/src/tools/clippy/tests/ui/single_match_else.rs
index 430c4da20f1..3f1fd2b3183 100644
--- a/src/tools/clippy/tests/ui/single_match_else.rs
+++ b/src/tools/clippy/tests/ui/single_match_else.rs
@@ -98,7 +98,7 @@ fn main() {
 
     // lint here
     use std::convert::Infallible;
-    match Result::<i32, Infallible>::Ok(1) {
+    match Result::<i32, &Infallible>::Ok(1) {
         Ok(a) => println!("${:?}", a),
         Err(_) => {
             println!("else block");
diff --git a/src/tools/clippy/tests/ui/single_match_else.stderr b/src/tools/clippy/tests/ui/single_match_else.stderr
index f8f88379d6d..61c348260d0 100644
--- a/src/tools/clippy/tests/ui/single_match_else.stderr
+++ b/src/tools/clippy/tests/ui/single_match_else.stderr
@@ -64,7 +64,7 @@ LL +     }
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
   --> tests/ui/single_match_else.rs:101:5
    |
-LL | /     match Result::<i32, Infallible>::Ok(1) {
+LL | /     match Result::<i32, &Infallible>::Ok(1) {
 LL | |         Ok(a) => println!("${:?}", a),
 LL | |         Err(_) => {
 LL | |             println!("else block");
@@ -75,7 +75,7 @@ LL | |     }
    |
 help: try
    |
-LL ~     if let Ok(a) = Result::<i32, Infallible>::Ok(1) { println!("${:?}", a) } else {
+LL ~     if let Ok(a) = Result::<i32, &Infallible>::Ok(1) { println!("${:?}", a) } else {
 LL +         println!("else block");
 LL +         return;
 LL +     }
diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.fixed b/src/tools/clippy/tests/ui/std_instead_of_core.fixed
index 6ede7bfcd9f..227b98c683e 100644
--- a/src/tools/clippy/tests/ui/std_instead_of_core.fixed
+++ b/src/tools/clippy/tests/ui/std_instead_of_core.fixed
@@ -75,8 +75,17 @@ mod std_in_proc_macro_derive {
     struct B {}
 }
 
-fn main() {
-    std_instead_of_core();
-    std_instead_of_alloc();
-    alloc_instead_of_core();
+// Some intrinsics are usable on stable but live in an unstable module, but should still suggest
+// replacing std -> core
+fn intrinsic(a: *mut u8, b: *mut u8) {
+    unsafe {
+        core::intrinsics::copy(a, b, 1);
+        //~^ std_instead_of_core
+    }
 }
+
+#[clippy::msrv = "1.76"]
+fn msrv_1_76(_: std::net::IpAddr) {}
+
+#[clippy::msrv = "1.77"]
+fn msrv_1_77(_: core::net::IpAddr) {}
diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.rs b/src/tools/clippy/tests/ui/std_instead_of_core.rs
index e22b4f61f3e..01bb78dd3bf 100644
--- a/src/tools/clippy/tests/ui/std_instead_of_core.rs
+++ b/src/tools/clippy/tests/ui/std_instead_of_core.rs
@@ -75,8 +75,17 @@ mod std_in_proc_macro_derive {
     struct B {}
 }
 
-fn main() {
-    std_instead_of_core();
-    std_instead_of_alloc();
-    alloc_instead_of_core();
+// Some intrinsics are usable on stable but live in an unstable module, but should still suggest
+// replacing std -> core
+fn intrinsic(a: *mut u8, b: *mut u8) {
+    unsafe {
+        std::intrinsics::copy(a, b, 1);
+        //~^ std_instead_of_core
+    }
 }
+
+#[clippy::msrv = "1.76"]
+fn msrv_1_76(_: std::net::IpAddr) {}
+
+#[clippy::msrv = "1.77"]
+fn msrv_1_77(_: std::net::IpAddr) {}
diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.stderr b/src/tools/clippy/tests/ui/std_instead_of_core.stderr
index 22cb9db7050..45d60d235ce 100644
--- a/src/tools/clippy/tests/ui/std_instead_of_core.stderr
+++ b/src/tools/clippy/tests/ui/std_instead_of_core.stderr
@@ -85,5 +85,17 @@ LL |     use alloc::slice::from_ref;
    = note: `-D clippy::alloc-instead-of-core` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::alloc_instead_of_core)]`
 
-error: aborting due to 13 previous errors
+error: used import from `std` instead of `core`
+  --> tests/ui/std_instead_of_core.rs:82:9
+   |
+LL |         std::intrinsics::copy(a, b, 1);
+   |         ^^^ help: consider importing the item from `core`: `core`
+
+error: used import from `std` instead of `core`
+  --> tests/ui/std_instead_of_core.rs:91:17
+   |
+LL | fn msrv_1_77(_: std::net::IpAddr) {}
+   |                 ^^^ help: consider importing the item from `core`: `core`
+
+error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.stderr b/src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.stderr
index 4faf0237c17..43b03676b1d 100644
--- a/src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.stderr
+++ b/src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.stderr
@@ -2,51 +2,84 @@ error: `^` is not the exponentiation operator
   --> tests/ui/suspicious_xor_used_as_pow.rs:19:13
    |
 LL |     let _ = 2 ^ 5;
-   |             ^^^^^ help: did you mean to write: `2.pow(5)`
+   |             ^^^^^
    |
    = note: `-D clippy::suspicious-xor-used-as-pow` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::suspicious_xor_used_as_pow)]`
+help: did you mean to write
+   |
+LL |     let _ = 2.pow(5);
+   |             ~~~~~~~~
 
 error: `^` is not the exponentiation operator
   --> tests/ui/suspicious_xor_used_as_pow.rs:22:13
    |
 LL |     let _ = 2i32 ^ 9i32;
-   |             ^^^^^^^^^^^ help: did you mean to write: `2i32.pow(9i32)`
+   |             ^^^^^^^^^^^
+   |
+help: did you mean to write
+   |
+LL |     let _ = 2i32.pow(9i32);
+   |             ~~~~~~~~~~~~~~
 
 error: `^` is not the exponentiation operator
   --> tests/ui/suspicious_xor_used_as_pow.rs:24:13
    |
 LL |     let _ = 2i32 ^ 2i32;
-   |             ^^^^^^^^^^^ help: did you mean to write: `2i32.pow(2i32)`
+   |             ^^^^^^^^^^^
+   |
+help: did you mean to write
+   |
+LL |     let _ = 2i32.pow(2i32);
+   |             ~~~~~~~~~~~~~~
 
 error: `^` is not the exponentiation operator
   --> tests/ui/suspicious_xor_used_as_pow.rs:26:13
    |
 LL |     let _ = 50i32 ^ 3i32;
-   |             ^^^^^^^^^^^^ help: did you mean to write: `50i32.pow(3i32)`
+   |             ^^^^^^^^^^^^
+   |
+help: did you mean to write
+   |
+LL |     let _ = 50i32.pow(3i32);
+   |             ~~~~~~~~~~~~~~~
 
 error: `^` is not the exponentiation operator
   --> tests/ui/suspicious_xor_used_as_pow.rs:28:13
    |
 LL |     let _ = 5i32 ^ 8i32;
-   |             ^^^^^^^^^^^ help: did you mean to write: `5i32.pow(8i32)`
+   |             ^^^^^^^^^^^
+   |
+help: did you mean to write
+   |
+LL |     let _ = 5i32.pow(8i32);
+   |             ~~~~~~~~~~~~~~
 
 error: `^` is not the exponentiation operator
   --> tests/ui/suspicious_xor_used_as_pow.rs:30:13
    |
 LL |     let _ = 2i32 ^ 32i32;
-   |             ^^^^^^^^^^^^ help: did you mean to write: `2i32.pow(32i32)`
+   |             ^^^^^^^^^^^^
+   |
+help: did you mean to write
+   |
+LL |     let _ = 2i32.pow(32i32);
+   |             ~~~~~~~~~~~~~~~
 
 error: `^` is not the exponentiation operator
   --> tests/ui/suspicious_xor_used_as_pow.rs:13:9
    |
 LL |         1 ^ 2 // should warn even if inside macro
-   |         ^^^^^ help: did you mean to write: `1.pow(2)`
+   |         ^^^^^
 ...
 LL |     macro_test_inside!();
    |     -------------------- in this macro invocation
    |
    = note: this error originates in the macro `macro_test_inside` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: did you mean to write
+   |
+LL |         1.pow(2) // should warn even if inside macro
+   |         ~~~~~~~~
 
 error: aborting due to 7 previous errors
 
diff --git a/src/tools/clippy/tests/ui/try_err.fixed b/src/tools/clippy/tests/ui/try_err.fixed
index aae4f8ac47f..f149bfb7774 100644
--- a/src/tools/clippy/tests/ui/try_err.fixed
+++ b/src/tools/clippy/tests/ui/try_err.fixed
@@ -1,5 +1,5 @@
 //@aux-build:proc_macros.rs
-
+#![feature(try_blocks)]
 #![deny(clippy::try_err)]
 #![allow(
     clippy::unnecessary_wraps,
@@ -152,3 +152,11 @@ pub fn try_return(x: bool) -> Result<i32, i32> {
     }
     Ok(0)
 }
+
+// Test that the lint is suppressed in try block.
+pub fn try_block() -> Result<(), i32> {
+    let _: Result<_, i32> = try {
+        Err(1)?;
+    };
+    Ok(())
+}
diff --git a/src/tools/clippy/tests/ui/try_err.rs b/src/tools/clippy/tests/ui/try_err.rs
index 927eccf2d54..841ec6b5d5c 100644
--- a/src/tools/clippy/tests/ui/try_err.rs
+++ b/src/tools/clippy/tests/ui/try_err.rs
@@ -1,5 +1,5 @@
 //@aux-build:proc_macros.rs
-
+#![feature(try_blocks)]
 #![deny(clippy::try_err)]
 #![allow(
     clippy::unnecessary_wraps,
@@ -152,3 +152,11 @@ pub fn try_return(x: bool) -> Result<i32, i32> {
     }
     Ok(0)
 }
+
+// Test that the lint is suppressed in try block.
+pub fn try_block() -> Result<(), i32> {
+    let _: Result<_, i32> = try {
+        Err(1)?;
+    };
+    Ok(())
+}
diff --git a/src/tools/clippy/tests/ui/uninit_vec.rs b/src/tools/clippy/tests/ui/uninit_vec.rs
index c069b9adf2d..0cc77a8775d 100644
--- a/src/tools/clippy/tests/ui/uninit_vec.rs
+++ b/src/tools/clippy/tests/ui/uninit_vec.rs
@@ -1,5 +1,6 @@
 #![warn(clippy::uninit_vec)]
 
+use std::cell::UnsafeCell;
 use std::mem::MaybeUninit;
 
 #[derive(Default)]
@@ -12,6 +13,12 @@ union MyOwnMaybeUninit {
     uninit: (),
 }
 
+// https://github.com/rust-lang/rust/issues/119620
+unsafe fn requires_paramenv<S>() {
+    let mut vec = Vec::<UnsafeCell<*mut S>>::with_capacity(1);
+    vec.set_len(1);
+}
+
 fn main() {
     // with_capacity() -> set_len() should be detected
     let mut vec: Vec<u8> = Vec::with_capacity(1000);
diff --git a/src/tools/clippy/tests/ui/uninit_vec.stderr b/src/tools/clippy/tests/ui/uninit_vec.stderr
index 8e93466c2cc..e8b77d653f0 100644
--- a/src/tools/clippy/tests/ui/uninit_vec.stderr
+++ b/src/tools/clippy/tests/ui/uninit_vec.stderr
@@ -1,5 +1,17 @@
 error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
-  --> tests/ui/uninit_vec.rs:17:5
+  --> tests/ui/uninit_vec.rs:18:5
+   |
+LL |     let mut vec = Vec::<UnsafeCell<*mut S>>::with_capacity(1);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     vec.set_len(1);
+   |     ^^^^^^^^^^^^^^
+   |
+   = help: initialize the buffer or wrap the content in `MaybeUninit`
+   = note: `-D clippy::uninit-vec` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::uninit_vec)]`
+
+error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
+  --> tests/ui/uninit_vec.rs:24:5
    |
 LL |     let mut vec: Vec<u8> = Vec::with_capacity(1000);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -8,11 +20,9 @@ LL |         vec.set_len(200);
    |         ^^^^^^^^^^^^^^^^
    |
    = help: initialize the buffer or wrap the content in `MaybeUninit`
-   = note: `-D clippy::uninit-vec` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::uninit_vec)]`
 
 error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
-  --> tests/ui/uninit_vec.rs:24:5
+  --> tests/ui/uninit_vec.rs:31:5
    |
 LL |     vec.reserve(1000);
    |     ^^^^^^^^^^^^^^^^^^
@@ -23,7 +33,7 @@ LL |         vec.set_len(200);
    = help: initialize the buffer or wrap the content in `MaybeUninit`
 
 error: calling `set_len()` on empty `Vec` creates out-of-bound values
-  --> tests/ui/uninit_vec.rs:31:5
+  --> tests/ui/uninit_vec.rs:38:5
    |
 LL |     let mut vec: Vec<u8> = Vec::new();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -32,7 +42,7 @@ LL |         vec.set_len(200);
    |         ^^^^^^^^^^^^^^^^
 
 error: calling `set_len()` on empty `Vec` creates out-of-bound values
-  --> tests/ui/uninit_vec.rs:38:5
+  --> tests/ui/uninit_vec.rs:45:5
    |
 LL |     let mut vec: Vec<u8> = Default::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -41,7 +51,7 @@ LL |         vec.set_len(200);
    |         ^^^^^^^^^^^^^^^^
 
 error: calling `set_len()` on empty `Vec` creates out-of-bound values
-  --> tests/ui/uninit_vec.rs:44:5
+  --> tests/ui/uninit_vec.rs:51:5
    |
 LL |     let mut vec: Vec<u8> = Vec::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -50,7 +60,7 @@ LL |         vec.set_len(200);
    |         ^^^^^^^^^^^^^^^^
 
 error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
-  --> tests/ui/uninit_vec.rs:61:5
+  --> tests/ui/uninit_vec.rs:68:5
    |
 LL |     let mut vec: Vec<u8> = Vec::with_capacity(1000);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -61,7 +71,7 @@ LL |         vec.set_len(200);
    = help: initialize the buffer or wrap the content in `MaybeUninit`
 
 error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
-  --> tests/ui/uninit_vec.rs:71:5
+  --> tests/ui/uninit_vec.rs:78:5
    |
 LL |     my_vec.vec.reserve(1000);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -72,7 +82,7 @@ LL |         my_vec.vec.set_len(200);
    = help: initialize the buffer or wrap the content in `MaybeUninit`
 
 error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
-  --> tests/ui/uninit_vec.rs:77:5
+  --> tests/ui/uninit_vec.rs:84:5
    |
 LL |     my_vec.vec = Vec::with_capacity(1000);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -83,7 +93,7 @@ LL |         my_vec.vec.set_len(200);
    = help: initialize the buffer or wrap the content in `MaybeUninit`
 
 error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
-  --> tests/ui/uninit_vec.rs:52:9
+  --> tests/ui/uninit_vec.rs:59:9
    |
 LL |         let mut vec: Vec<u8> = Vec::with_capacity(1000);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -94,7 +104,7 @@ LL |         vec.set_len(200);
    = help: initialize the buffer or wrap the content in `MaybeUninit`
 
 error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
-  --> tests/ui/uninit_vec.rs:56:9
+  --> tests/ui/uninit_vec.rs:63:9
    |
 LL |         vec.reserve(1000);
    |         ^^^^^^^^^^^^^^^^^^
@@ -105,7 +115,7 @@ LL |         vec.set_len(200);
    = help: initialize the buffer or wrap the content in `MaybeUninit`
 
 error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
-  --> tests/ui/uninit_vec.rs:132:9
+  --> tests/ui/uninit_vec.rs:139:9
    |
 LL |         let mut vec: Vec<T> = Vec::with_capacity(1000);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -115,5 +125,5 @@ LL |             vec.set_len(10);
    |
    = help: initialize the buffer or wrap the content in `MaybeUninit`
 
-error: aborting due to 11 previous errors
+error: aborting due to 12 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr
index 15708090361..37ee9195fce 100644
--- a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr
@@ -63,7 +63,7 @@ LL |     let _val = None::<()>.expect("this always happens");
 help: remove the `None` and `expect()`
    |
 LL |     let _val = panic!("this always happens");
-   |                ~~~~~~~                     ~
+   |                ~~~~~~~
 
 error: used `unwrap_or_default()` on `None` value
   --> tests/ui/unnecessary_literal_unwrap.rs:22:24
@@ -134,7 +134,7 @@ LL |     None::<()>.expect("this always happens");
 help: remove the `None` and `expect()`
    |
 LL |     panic!("this always happens");
-   |     ~~~~~~~                     ~
+   |     ~~~~~~~
 
 error: used `unwrap_or_default()` on `None` value
   --> tests/ui/unnecessary_literal_unwrap.rs:30:5
diff --git a/src/tools/clippy/tests/ui/unnecessary_wraps.stderr b/src/tools/clippy/tests/ui/unnecessary_wraps.stderr
index a55a23d449f..59986d895b3 100644
--- a/src/tools/clippy/tests/ui/unnecessary_wraps.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_wraps.stderr
@@ -118,8 +118,8 @@ LL | | }
    |
 help: remove the return type...
    |
-LL | fn issue_6640_1(a: bool, b: bool) -> Option<()> {
-   |                                      ~~~~~~~~~~
+LL | fn issue_6640_1(a: bool, b: bool) -> () {
+   |                                      ~~
 help: ...and then remove returned values
    |
 LL ~         return ;
@@ -145,8 +145,8 @@ LL | | }
    |
 help: remove the return type...
    |
-LL | fn issue_6640_2(a: bool, b: bool) -> Result<(), i32> {
-   |                                      ~~~~~~~~~~~~~~~
+LL | fn issue_6640_2(a: bool, b: bool) -> () {
+   |                                      ~~
 help: ...and then remove returned values
    |
 LL ~         return ;
diff --git a/src/tools/clippy/tests/ui/unneeded_field_pattern.rs b/src/tools/clippy/tests/ui/unneeded_field_pattern.rs
index 0dc21f4ce94..1d42f81711b 100644
--- a/src/tools/clippy/tests/ui/unneeded_field_pattern.rs
+++ b/src/tools/clippy/tests/ui/unneeded_field_pattern.rs
@@ -1,6 +1,6 @@
 //@aux-build:proc_macros.rs
 #![warn(clippy::unneeded_field_pattern)]
-#![allow(dead_code, unused)]
+#![allow(dead_code, unused, clippy::single_match)]
 
 #[macro_use]
 extern crate proc_macros;
diff --git a/src/tools/clippy/tests/ui/unused_result_ok.fixed b/src/tools/clippy/tests/ui/unused_result_ok.fixed
new file mode 100644
index 00000000000..e78fde5c9e3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_result_ok.fixed
@@ -0,0 +1,40 @@
+//@aux-build:proc_macros.rs
+#![warn(clippy::unused_result_ok)]
+#![allow(dead_code)]
+
+#[macro_use]
+extern crate proc_macros;
+
+fn bad_style(x: &str) {
+    let _ = x.parse::<u32>();
+}
+
+fn good_style(x: &str) -> Option<u32> {
+    x.parse::<u32>().ok()
+}
+
+#[rustfmt::skip]
+fn strange_parse(x: &str) {
+    let _ = x   .   parse::<i32>();
+}
+
+macro_rules! v {
+    () => {
+        Ok::<(), ()>(())
+    };
+}
+
+macro_rules! w {
+    () => {
+        let _ = Ok::<(), ()>(());
+    };
+}
+
+fn main() {
+    let _ = v!();
+    w!();
+
+    external! {
+        Ok::<(),()>(()).ok();
+    };
+}
diff --git a/src/tools/clippy/tests/ui/unused_result_ok.rs b/src/tools/clippy/tests/ui/unused_result_ok.rs
new file mode 100644
index 00000000000..117d64c4cec
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_result_ok.rs
@@ -0,0 +1,40 @@
+//@aux-build:proc_macros.rs
+#![warn(clippy::unused_result_ok)]
+#![allow(dead_code)]
+
+#[macro_use]
+extern crate proc_macros;
+
+fn bad_style(x: &str) {
+    x.parse::<u32>().ok();
+}
+
+fn good_style(x: &str) -> Option<u32> {
+    x.parse::<u32>().ok()
+}
+
+#[rustfmt::skip]
+fn strange_parse(x: &str) {
+    x   .   parse::<i32>()   .   ok   ();
+}
+
+macro_rules! v {
+    () => {
+        Ok::<(), ()>(())
+    };
+}
+
+macro_rules! w {
+    () => {
+        Ok::<(), ()>(()).ok();
+    };
+}
+
+fn main() {
+    v!().ok();
+    w!();
+
+    external! {
+        Ok::<(),()>(()).ok();
+    };
+}
diff --git a/src/tools/clippy/tests/ui/unused_result_ok.stderr b/src/tools/clippy/tests/ui/unused_result_ok.stderr
new file mode 100644
index 00000000000..241e0c71261
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_result_ok.stderr
@@ -0,0 +1,52 @@
+error: ignoring a result with `.ok()` is misleading
+  --> tests/ui/unused_result_ok.rs:9:5
+   |
+LL |     x.parse::<u32>().ok();
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::unused-result-ok` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::unused_result_ok)]`
+help: consider using `let _ =` and removing the call to `.ok()` instead
+   |
+LL |     let _ = x.parse::<u32>();
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: ignoring a result with `.ok()` is misleading
+  --> tests/ui/unused_result_ok.rs:18:5
+   |
+LL |     x   .   parse::<i32>()   .   ok   ();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using `let _ =` and removing the call to `.ok()` instead
+   |
+LL |     let _ = x   .   parse::<i32>();
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: ignoring a result with `.ok()` is misleading
+  --> tests/ui/unused_result_ok.rs:34:5
+   |
+LL |     v!().ok();
+   |     ^^^^^^^^^
+   |
+help: consider using `let _ =` and removing the call to `.ok()` instead
+   |
+LL |     let _ = v!();
+   |     ~~~~~~~~~~~~
+
+error: ignoring a result with `.ok()` is misleading
+  --> tests/ui/unused_result_ok.rs:29:9
+   |
+LL |         Ok::<(), ()>(()).ok();
+   |         ^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     w!();
+   |     ---- in this macro invocation
+   |
+   = note: this error originates in the macro `w` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider using `let _ =` and removing the call to `.ok()` instead
+   |
+LL |         let _ = Ok::<(), ()>(());
+   |         ~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unwrap_expect_used.rs b/src/tools/clippy/tests/ui/unwrap_expect_used.rs
index 96368a07053..a56bd0a8d07 100644
--- a/src/tools/clippy/tests/ui/unwrap_expect_used.rs
+++ b/src/tools/clippy/tests/ui/unwrap_expect_used.rs
@@ -31,7 +31,7 @@ fn main() {
 
     // Don't trigger on unwrap_err on an option
     Some(3).unwrap_err();
-    Some(3).expect_err("Hellow none!");
+    Some(3).expect_err("Hello none!");
 
     // Issue #11245: The `Err` variant can never be constructed so do not lint this.
     let x: Result<(), !> = Ok(());
diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.fixed b/src/tools/clippy/tests/ui/while_let_on_iterator.fixed
index 59b5c858d04..b8087c6e000 100644
--- a/src/tools/clippy/tests/ui/while_let_on_iterator.fixed
+++ b/src/tools/clippy/tests/ui/while_let_on_iterator.fixed
@@ -456,6 +456,15 @@ fn fn_once_closure() {
     });
 }
 
+fn issue13123() {
+    let mut it = 0..20;
+    'label: for n in it {
+        if n % 25 == 0 {
+            break 'label;
+        }
+    }
+}
+
 fn main() {
     let mut it = 0..20;
     for _ in it {
diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.rs b/src/tools/clippy/tests/ui/while_let_on_iterator.rs
index 559513d5694..8e02f59b512 100644
--- a/src/tools/clippy/tests/ui/while_let_on_iterator.rs
+++ b/src/tools/clippy/tests/ui/while_let_on_iterator.rs
@@ -456,6 +456,15 @@ fn fn_once_closure() {
     });
 }
 
+fn issue13123() {
+    let mut it = 0..20;
+    'label: while let Some(n) = it.next() {
+        if n % 25 == 0 {
+            break 'label;
+        }
+    }
+}
+
 fn main() {
     let mut it = 0..20;
     while let Some(..) = it.next() {
diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.stderr b/src/tools/clippy/tests/ui/while_let_on_iterator.stderr
index 8ff1f23644b..d96b26acf34 100644
--- a/src/tools/clippy/tests/ui/while_let_on_iterator.stderr
+++ b/src/tools/clippy/tests/ui/while_let_on_iterator.stderr
@@ -160,8 +160,14 @@ LL |         while let Some(x) = it.next() {
 error: this loop could be written as a `for` loop
   --> tests/ui/while_let_on_iterator.rs:461:5
    |
+LL |     'label: while let Some(n) = it.next() {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'label: for n in it`
+
+error: this loop could be written as a `for` loop
+  --> tests/ui/while_let_on_iterator.rs:470:5
+   |
 LL |     while let Some(..) = it.next() {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in it`
 
-error: aborting due to 27 previous errors
+error: aborting due to 28 previous errors
 
diff --git a/src/tools/clippy/tests/versioncheck.rs b/src/tools/clippy/tests/versioncheck.rs
index eba5405e67e..68328333937 100644
--- a/src/tools/clippy/tests/versioncheck.rs
+++ b/src/tools/clippy/tests/versioncheck.rs
@@ -1,4 +1,3 @@
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![warn(rust_2018_idioms, unused_lifetimes)]
 #![allow(clippy::single_match_else)]
 
diff --git a/src/tools/clippy/tests/workspace_test/path_dep/Cargo.toml b/src/tools/clippy/tests/workspace_test/path_dep/Cargo.toml
index 85a91cd2dec..98b4fb7aa50 100644
--- a/src/tools/clippy/tests/workspace_test/path_dep/Cargo.toml
+++ b/src/tools/clippy/tests/workspace_test/path_dep/Cargo.toml
@@ -1,3 +1,6 @@
 [package]
 name = "path_dep"
 version = "0.1.0"
+
+[features]
+primary_package_test = []
diff --git a/src/tools/clippy/util/gh-pages/index.html b/src/tools/clippy/util/gh-pages/index.html
index 0c0f28e4fbd..300c9de178f 100644
--- a/src/tools/clippy/util/gh-pages/index.html
+++ b/src/tools/clippy/util/gh-pages/index.html
@@ -541,7 +541,7 @@ Otherwise, have a great day =^.^=
                     <div class="col-12 col-md-5 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"
+                            <input type="text" class="form-control filter-input" placeholder="Keywords or search string (`S` or `/` to focus)" id="search-input"
                                 ng-model="search" ng-blur="updatePath()" ng-keyup="$event.keyCode == 13 && updatePath()"
                                 ng-model-options="{debounce: 50}" />
                             <span class="input-group-btn">
@@ -605,7 +605,7 @@ Otherwise, have a great day =^.^=
                             <a href="https://github.com/rust-lang/rust-clippy/issues?q=is%3Aissue+{{lint.id}}">Related Issues</a>
                         </div>
                         <!-- Jump to source -->
-                        <div class="lint-additional-info-item">
+                        <div class="lint-additional-info-item" ng-if="lint.id_span">
                             <a href="https://github.com/rust-lang/rust-clippy/blob/{{docVersion}}/clippy_lints/{{lint.id_span.path}}#L{{lint.id_span.line}}">View Source</a>
                         </div>
                     </div>
diff --git a/src/tools/clippy/util/gh-pages/script.js b/src/tools/clippy/util/gh-pages/script.js
index 661f80a6d34..ed1e090e1b5 100644
--- a/src/tools/clippy/util/gh-pages/script.js
+++ b/src/tools/clippy/util/gh-pages/script.js
@@ -1,5 +1,5 @@
 (function () {
-    var md = window.markdownit({
+    const md = window.markdownit({
         html: true,
         linkify: true,
         typographer: true,
@@ -17,7 +17,7 @@
     });
 
     function scrollToLint(lintId) {
-        var target = document.getElementById(lintId);
+        const target = document.getElementById(lintId);
         if (!target) {
             return;
         }
@@ -25,21 +25,17 @@
     }
 
     function scrollToLintByURL($scope, $location) {
-        var removeListener = $scope.$on('ngRepeatFinished', function (ngRepeatFinishedEvent) {
+        const removeListener = $scope.$on('ngRepeatFinished', function (ngRepeatFinishedEvent) {
             scrollToLint($location.path().substring(1));
             removeListener();
         });
     }
 
     function selectGroup($scope, selectedGroup) {
-        var groups = $scope.groups;
-        for (var group in groups) {
+        const groups = $scope.groups;
+        for (const group in groups) {
             if (groups.hasOwnProperty(group)) {
-                if (group === selectedGroup) {
-                    groups[group] = true;
-                } else {
-                    groups[group] = false;
-                }
+                groups[group] = group === selectedGroup;
             }
         }
     }
@@ -108,7 +104,7 @@
         })
         .controller("lintList", function ($scope, $http, $location, $timeout) {
             // Level filter
-            var LEVEL_FILTERS_DEFAULT = {allow: true, warn: true, deny: true, none: true};
+            const LEVEL_FILTERS_DEFAULT = {allow: true, warn: true, deny: true, none: true};
             $scope.levels = { ...LEVEL_FILTERS_DEFAULT };
             $scope.byLevels = function (lint) {
                 return $scope.levels[lint.level];
@@ -367,7 +363,7 @@
             }
 
             $scope.clearVersionFilters = function () {
-                for (let filter in $scope.versionFilters) {
+                for (const filter in $scope.versionFilters) {
                     $scope.versionFilters[filter] = { enabled: false, minorVersion: null };
                 }
             }
@@ -378,7 +374,7 @@
 
             $scope.updateVersionFilters = function() {
                 for (const filter in $scope.versionFilters) {
-                    let minorVersion = $scope.versionFilters[filter].minorVersion;
+                    const minorVersion = $scope.versionFilters[filter].minorVersion;
 
                     // 1.29.0 and greater
                     if (minorVersion && minorVersion > 28) {
@@ -391,14 +387,14 @@
             }
 
             $scope.byVersion = function(lint) {
-                let filters = $scope.versionFilters;
+                const filters = $scope.versionFilters;
                 for (const filter in filters) {
                     if (filters[filter].enabled) {
-                        let minorVersion = filters[filter].minorVersion;
+                        const minorVersion = filters[filter].minorVersion;
 
                         // Strip the "pre " prefix for pre 1.29.0 lints
-                        let lintVersion = lint.version.startsWith("pre ") ? lint.version.substring(4, lint.version.length) : lint.version;
-                        let lintMinorVersion = lintVersion.substring(2, 4);
+                        const lintVersion = lint.version.startsWith("pre ") ? lint.version.substring(4, lint.version.length) : lint.version;
+                        const lintMinorVersion = lintVersion.substring(2, 4);
 
                         switch (filter) {
                             // "=" gets the highest priority, since all filters are inclusive
@@ -441,8 +437,8 @@
 
                 // Search the description
                 // The use of `for`-loops instead of `foreach` enables us to return early
-                let terms = searchStr.split(" ");
-                let docsLowerCase = lint.docs.toLowerCase();
+                const terms = searchStr.split(" ");
+                const docsLowerCase = lint.docs.toLowerCase();
                 for (index = 0; index < terms.length; index++) {
                     // This is more likely and will therefore be checked first
                     if (docsLowerCase.indexOf(terms[index]) !== -1) {
@@ -479,7 +475,7 @@
                 const clipboard = document.getElementById("clipboard-" + lint.id);
                 if (clipboard) {
                     let resetClipboardTimeout = null;
-                    let resetClipboardIcon = clipboard.innerHTML;
+                    const resetClipboardIcon = clipboard.innerHTML;
 
                     function resetClipboard() {
                         resetClipboardTimeout = null;
@@ -511,7 +507,7 @@
                     $scope.data = data;
                     $scope.loading = false;
 
-                    var selectedGroup = getQueryVariable("sel");
+                    const selectedGroup = getQueryVariable("sel");
                     if (selectedGroup) {
                         selectGroup($scope, selectedGroup.toLowerCase());
                     }
@@ -519,7 +515,7 @@
                     scrollToLintByURL($scope, $location);
 
                     setTimeout(function () {
-                        var el = document.getElementById('filter-input');
+                        const el = document.getElementById('filter-input');
                         if (el) { el.focus() }
                     }, 0);
                 })
@@ -531,10 +527,10 @@
 })();
 
 function getQueryVariable(variable) {
-    var query = window.location.search.substring(1);
-    var vars = query.split('&');
-    for (var i = 0; i < vars.length; i++) {
-        var pair = vars[i].split('=');
+    const query = window.location.search.substring(1);
+    const vars = query.split('&');
+    for (const entry of vars) {
+        const pair = entry.split('=');
         if (decodeURIComponent(pair[0]) == variable) {
             return decodeURIComponent(pair[1]);
         }
@@ -579,6 +575,32 @@ function setTheme(theme, store) {
     }
 }
 
+function handleShortcut(ev) {
+    if (ev.ctrlKey || ev.altKey || ev.metaKey) {
+        return;
+    }
+
+    if (document.activeElement.tagName === "INPUT") {
+        if (ev.key === "Escape") {
+            document.activeElement.blur();
+        }
+    } else {
+        switch (ev.key) {
+            case "s":
+            case "S":
+            case "/":
+                ev.preventDefault(); // To prevent the key to be put into the input.
+                document.getElementById("search-input").focus();
+                break;
+            default:
+                break;
+        }
+    }
+}
+
+document.addEventListener("keypress", handleShortcut);
+document.addEventListener("keydown", handleShortcut);
+
 // loading the theme after the initial load
 const prefersDark = window.matchMedia("(prefers-color-scheme: dark)");
 const theme = localStorage.getItem('clippy-lint-list-theme');
diff --git a/src/tools/collect-license-metadata/Cargo.toml b/src/tools/collect-license-metadata/Cargo.toml
index d0820cfc2a0..edf9e5c5393 100644
--- a/src/tools/collect-license-metadata/Cargo.toml
+++ b/src/tools/collect-license-metadata/Cargo.toml
@@ -2,6 +2,8 @@
 name = "collect-license-metadata"
 version = "0.1.0"
 edition = "2021"
+description = "Runs the reuse tool and caches the output, so rust toolchain devs don't need to have reuse installed"
+license = "MIT OR Apache-2.0"
 
 [dependencies]
 anyhow = "1.0.65"
diff --git a/src/tools/collect-license-metadata/src/main.rs b/src/tools/collect-license-metadata/src/main.rs
index ca2a6f4b8c8..dce36bb17b6 100644
--- a/src/tools/collect-license-metadata/src/main.rs
+++ b/src/tools/collect-license-metadata/src/main.rs
@@ -2,10 +2,17 @@ mod licenses;
 mod path_tree;
 mod reuse;
 
-use crate::licenses::LicensesInterner;
-use anyhow::Error;
 use std::path::PathBuf;
 
+use anyhow::Error;
+
+use crate::licenses::LicensesInterner;
+
+/// The entry point to the binary.
+///
+/// You should probably let `bootstrap` execute this program instead of running it directly.
+///
+/// Run `x.py run collect-license-metadata`
 fn main() -> Result<(), Error> {
     let reuse_exe: PathBuf = std::env::var_os("REUSE_EXE").expect("Missing REUSE_EXE").into();
     let dest: PathBuf = std::env::var_os("DEST").expect("Missing DEST").into();
diff --git a/src/tools/collect-license-metadata/src/path_tree.rs b/src/tools/collect-license-metadata/src/path_tree.rs
index b27fb7f9225..866a4e42aab 100644
--- a/src/tools/collect-license-metadata/src/path_tree.rs
+++ b/src/tools/collect-license-metadata/src/path_tree.rs
@@ -3,10 +3,11 @@
 //! responsible for that, by turning the list of paths into a tree and executing simplification
 //! passes over the tree to remove redundant information.
 
-use crate::licenses::{License, LicenseId, LicensesInterner};
 use std::collections::BTreeMap;
 use std::path::{Path, PathBuf};
 
+use crate::licenses::{License, LicenseId, LicensesInterner};
+
 #[derive(serde::Serialize)]
 #[serde(rename_all = "kebab-case", tag = "type")]
 pub(crate) enum Node<L> {
diff --git a/src/tools/collect-license-metadata/src/reuse.rs b/src/tools/collect-license-metadata/src/reuse.rs
index a5d01935f76..e5ee8f0da5e 100644
--- a/src/tools/collect-license-metadata/src/reuse.rs
+++ b/src/tools/collect-license-metadata/src/reuse.rs
@@ -1,9 +1,11 @@
-use crate::licenses::{License, LicenseId, LicensesInterner};
-use anyhow::Error;
 use std::path::{Path, PathBuf};
 use std::process::{Command, Stdio};
 use std::time::Instant;
 
+use anyhow::Error;
+
+use crate::licenses::{License, LicenseId, LicensesInterner};
+
 pub(crate) fn collect(
     reuse_exe: &Path,
     interner: &mut LicensesInterner,
diff --git a/src/tools/compiletest/src/command-list.rs b/src/tools/compiletest/src/command-list.rs
index c356f4266f0..50c909793f5 100644
--- a/src/tools/compiletest/src/command-list.rs
+++ b/src/tools/compiletest/src/command-list.rs
@@ -18,6 +18,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "check-test-line-numbers-match",
     "compare-output-lines-by-subset",
     "compile-flags",
+    "doc-flags",
     "dont-check-compiler-stderr",
     "dont-check-compiler-stdout",
     "dont-check-failure-status",
@@ -117,6 +118,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "ignore-watchos",
     "ignore-windows",
     "ignore-windows-gnu",
+    "ignore-windows-msvc",
     "ignore-x32",
     "ignore-x86",
     "ignore-x86_64",
@@ -168,6 +170,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "only-32bit",
     "only-64bit",
     "only-aarch64",
+    "only-aarch64-unknown-linux-gnu",
     "only-apple",
     "only-arm",
     "only-avr",
@@ -202,6 +205,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "only-watchos",
     "only-windows",
     "only-windows-gnu",
+    "only-windows-msvc",
     "only-x86",
     "only-x86_64",
     "only-x86_64-fortanix-unknown-sgx",
@@ -225,6 +229,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "should-ice",
     "stderr-per-bitwidth",
     "test-mir-pass",
+    "unique-doc-out-dir",
     "unset-exec-env",
     "unset-rustc-env",
     // Used by the tidy check `unknown_revision`.
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index bc66dcbfb94..70ebefe3f41 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -1,19 +1,18 @@
-pub use self::Mode::*;
-
+use std::collections::{HashMap, HashSet};
 use std::ffi::OsString;
-use std::fmt;
-use std::iter;
 use std::path::{Path, PathBuf};
 use std::process::Command;
 use std::str::FromStr;
 use std::sync::OnceLock;
+use std::{fmt, iter};
 
-use crate::util::{add_dylib_path, PathBufExt};
 use build_helper::git::GitConfig;
 use serde::de::{Deserialize, Deserializer, Error as _};
-use std::collections::{HashMap, HashSet};
 use test::{ColorConfig, OutputFormat};
 
+pub use self::Mode::*;
+use crate::util::{add_dylib_path, PathBufExt};
+
 macro_rules! string_enum {
     ($(#[$meta:meta])* $vis:vis enum $name:ident { $($variant:ident => $repr:expr,)* }) => {
         $(#[$meta])*
diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs
index 7a5abc51d04..4ca9f02ddc7 100644
--- a/src/tools/compiletest/src/errors.rs
+++ b/src/tools/compiletest/src/errors.rs
@@ -1,5 +1,3 @@
-use self::WhichLine::*;
-
 use std::fmt;
 use std::fs::File;
 use std::io::prelude::*;
@@ -11,6 +9,8 @@ use std::sync::OnceLock;
 use regex::Regex;
 use tracing::*;
 
+use self::WhichLine::*;
+
 #[derive(Copy, Clone, Debug, PartialEq)]
 pub enum ErrorKind {
     Help,
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 3afb5e27547..1fc24301c85 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -11,8 +11,7 @@ use regex::Regex;
 use tracing::*;
 
 use crate::common::{Config, Debugger, FailMode, Mode, PassMode};
-use crate::header::cfg::parse_cfg_name_directive;
-use crate::header::cfg::MatchOutcome;
+use crate::header::cfg::{parse_cfg_name_directive, MatchOutcome};
 use crate::header::needs::CachedNeedsConditions;
 use crate::util::static_regex;
 use crate::{extract_cdb_version, extract_gdb_version};
@@ -96,6 +95,8 @@ pub struct TestProps {
     pub compile_flags: Vec<String>,
     // Extra flags to pass when the compiled code is run (such as --bench)
     pub run_flags: Vec<String>,
+    /// Extra flags to pass to rustdoc but not the compiler.
+    pub doc_flags: Vec<String>,
     // If present, the name of a file that this test should match when
     // pretty-printed
     pub pp_exact: Option<PathBuf>,
@@ -123,6 +124,9 @@ pub struct TestProps {
     pub unset_exec_env: Vec<String>,
     // Build documentation for all specified aux-builds as well
     pub build_aux_docs: bool,
+    /// Build the documentation for each crate in a unique output directory.
+    /// Uses <root output directory>/docs/<test name>/doc
+    pub unique_doc_out_dir: bool,
     // Flag to force a crate to be built with the host architecture
     pub force_host: bool,
     // Check stdout for error-pattern output as well as stderr
@@ -221,8 +225,10 @@ mod directives {
     pub const REGEX_ERROR_PATTERN: &'static str = "regex-error-pattern";
     pub const COMPILE_FLAGS: &'static str = "compile-flags";
     pub const RUN_FLAGS: &'static str = "run-flags";
+    pub const DOC_FLAGS: &'static str = "doc-flags";
     pub const SHOULD_ICE: &'static str = "should-ice";
     pub const BUILD_AUX_DOCS: &'static str = "build-aux-docs";
+    pub const UNIQUE_DOC_OUT_DIR: &'static str = "unique-doc-out-dir";
     pub const FORCE_HOST: &'static str = "force-host";
     pub const CHECK_STDOUT: &'static str = "check-stdout";
     pub const CHECK_RUN_RESULTS: &'static str = "check-run-results";
@@ -268,6 +274,7 @@ impl TestProps {
             regex_error_patterns: vec![],
             compile_flags: vec![],
             run_flags: vec![],
+            doc_flags: vec![],
             pp_exact: None,
             aux_builds: vec![],
             aux_bins: vec![],
@@ -282,6 +289,7 @@ impl TestProps {
             exec_env: vec![],
             unset_exec_env: vec![],
             build_aux_docs: false,
+            unique_doc_out_dir: false,
             force_host: false,
             check_stdout: false,
             check_run_results: false,
@@ -331,6 +339,7 @@ impl TestProps {
     pub fn from_file(testfile: &Path, revision: Option<&str>, config: &Config) -> Self {
         let mut props = TestProps::new();
         props.load_from(testfile, revision, config);
+        props.exec_env.push(("RUSTC".to_string(), config.rustc_path.display().to_string()));
 
         match (props.pass_mode, props.fail_mode) {
             (None, None) if config.mode == Mode::Ui => props.fail_mode = Some(FailMode::Check),
@@ -378,6 +387,8 @@ impl TestProps {
                         |r| r,
                     );
 
+                    config.push_name_value_directive(ln, DOC_FLAGS, &mut self.doc_flags, |r| r);
+
                     fn split_flags(flags: &str) -> Vec<String> {
                         // Individual flags can be single-quoted to preserve spaces; see
                         // <https://github.com/rust-lang/rust/pull/115948/commits/957c5db6>.
@@ -415,6 +426,8 @@ impl TestProps {
 
                     config.set_name_directive(ln, SHOULD_ICE, &mut self.should_ice);
                     config.set_name_directive(ln, BUILD_AUX_DOCS, &mut self.build_aux_docs);
+                    config.set_name_directive(ln, UNIQUE_DOC_OUT_DIR, &mut self.unique_doc_out_dir);
+
                     config.set_name_directive(ln, FORCE_HOST, &mut self.force_host);
                     config.set_name_directive(ln, CHECK_STDOUT, &mut self.check_stdout);
                     config.set_name_directive(ln, CHECK_RUN_RESULTS, &mut self.check_run_results);
diff --git a/src/tools/compiletest/src/header/cfg.rs b/src/tools/compiletest/src/header/cfg.rs
index 522c52b1de2..948568e63c2 100644
--- a/src/tools/compiletest/src/header/cfg.rs
+++ b/src/tools/compiletest/src/header/cfg.rs
@@ -1,6 +1,7 @@
+use std::collections::HashSet;
+
 use crate::common::{CompareMode, Config, Debugger, Mode};
 use crate::header::IgnoreDecision;
-use std::collections::HashSet;
 
 const EXTRA_ARCHS: &[&str] = &["spirv"];
 
diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs
index c790eb18d67..29e11e77f1c 100644
--- a/src/tools/compiletest/src/header/tests.rs
+++ b/src/tools/compiletest/src/header/tests.rs
@@ -2,11 +2,10 @@ use std::io::Read;
 use std::path::Path;
 use std::str::FromStr;
 
+use super::iter_header;
 use crate::common::{Config, Debugger, Mode};
 use crate::header::{parse_normalize_rule, EarlyProps, HeadersCache};
 
-use super::iter_header;
-
 fn make_test_description<R: Read>(
     config: &Config,
     name: test::TestName,
diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs
index 29e8809e5bd..76b83f02b14 100644
--- a/src/tools/compiletest/src/json.rs
+++ b/src/tools/compiletest/src/json.rs
@@ -1,12 +1,14 @@
 //! These structs are a subset of the ones found in `rustc_errors::json`.
 //! They are only used for deserialization of JSON output provided by libtest.
 
-use crate::errors::{Error, ErrorKind};
-use crate::runtest::ProcRes;
-use serde::Deserialize;
 use std::path::{Path, PathBuf};
 use std::str::FromStr;
 
+use serde::Deserialize;
+
+use crate::errors::{Error, ErrorKind};
+use crate::runtest::ProcRes;
+
 #[derive(Deserialize)]
 struct Diagnostic {
     message: String,
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index 81a5acb5cf2..6acf46f9196 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -18,27 +18,29 @@ mod read2;
 pub mod runtest;
 pub mod util;
 
-use crate::common::{expected_output_path, output_base_dir, output_relative_path, UI_EXTENSIONS};
-use crate::common::{Config, Debugger, Mode, PassMode, TestPaths};
-use crate::util::logv;
-use build_helper::git::{get_git_modified_files, get_git_untracked_files};
 use core::panic;
-use getopts::Options;
 use std::collections::HashSet;
 use std::ffi::{OsStr, OsString};
-use std::fs;
 use std::io::{self, ErrorKind};
 use std::path::{Path, PathBuf};
 use std::process::{Command, Stdio};
 use std::sync::{Arc, OnceLock};
 use std::time::SystemTime;
-use std::{env, vec};
+use std::{env, fs, vec};
+
+use build_helper::git::{get_git_modified_files, get_git_untracked_files};
+use getopts::Options;
 use test::ColorConfig;
 use tracing::*;
 use walkdir::WalkDir;
 
 use self::header::{make_test_description, EarlyProps};
+use crate::common::{
+    expected_output_path, output_base_dir, output_relative_path, Config, Debugger, Mode, PassMode,
+    TestPaths, UI_EXTENSIONS,
+};
 use crate::header::HeadersCache;
+use crate::util::logv;
 
 pub fn parse_config(args: Vec<String>) -> Config {
     let mut opts = Options::new();
diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs
index 1ec3f0a0552..7b85e6f80b3 100644
--- a/src/tools/compiletest/src/main.rs
+++ b/src/tools/compiletest/src/main.rs
@@ -1,6 +1,9 @@
-use std::{env, io::IsTerminal, sync::Arc};
+use std::env;
+use std::io::IsTerminal;
+use std::sync::Arc;
 
-use compiletest::{common::Mode, log_config, parse_config, run_tests};
+use compiletest::common::Mode;
+use compiletest::{log_config, parse_config, run_tests};
 
 fn main() {
     tracing_subscriber::fmt::init();
diff --git a/src/tools/compiletest/src/raise_fd_limit.rs b/src/tools/compiletest/src/raise_fd_limit.rs
index 218bea68a21..4445ecb7ce8 100644
--- a/src/tools/compiletest/src/raise_fd_limit.rs
+++ b/src/tools/compiletest/src/raise_fd_limit.rs
@@ -7,10 +7,9 @@
 #[cfg(target_vendor = "apple")]
 #[allow(non_camel_case_types)]
 pub unsafe fn raise_fd_limit() {
-    use std::cmp;
-    use std::io;
     use std::mem::size_of_val;
     use std::ptr::null_mut;
+    use std::{cmp, io};
 
     static CTL_KERN: libc::c_int = 1;
     static KERN_MAXFILESPERPROC: libc::c_int = 29;
diff --git a/src/tools/compiletest/src/read2.rs b/src/tools/compiletest/src/read2.rs
index 8c06339f3c3..b2d068e78b4 100644
--- a/src/tools/compiletest/src/read2.rs
+++ b/src/tools/compiletest/src/read2.rs
@@ -4,10 +4,11 @@
 #[cfg(test)]
 mod tests;
 
-pub use self::imp::read2;
 use std::io::{self, Write};
 use std::process::{Child, Output};
 
+pub use self::imp::read2;
+
 #[derive(Copy, Clone, Debug)]
 pub enum Truncated {
     Yes,
@@ -154,11 +155,10 @@ mod imp {
 
 #[cfg(unix)]
 mod imp {
-    use std::io;
     use std::io::prelude::*;
-    use std::mem;
     use std::os::unix::prelude::*;
     use std::process::{ChildStderr, ChildStdout};
+    use std::{io, mem};
 
     pub fn read2(
         mut out_pipe: ChildStdout,
@@ -228,10 +228,9 @@ mod imp {
 
 #[cfg(windows)]
 mod imp {
-    use std::io;
     use std::os::windows::prelude::*;
     use std::process::{ChildStderr, ChildStdout};
-    use std::slice;
+    use std::{io, slice};
 
     use miow::iocp::{CompletionPort, CompletionStatus};
     use miow::pipe::NamedPipe;
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 78c06551ff2..59fce44d1c7 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1,45 +1,38 @@
 // ignore-tidy-filelength
 
-use crate::common::{
-    expected_output_path, UI_EXTENSIONS, UI_FIXED, UI_STDERR, UI_STDOUT, UI_SVG, UI_WINDOWS_SVG,
-};
-use crate::common::{incremental_dir, output_base_dir, output_base_name, output_testname_unique};
-use crate::common::{Assembly, Crashes, Incremental, JsDocTest, MirOpt, RunMake, RustdocJson, Ui};
-use crate::common::{Codegen, CodegenUnits, DebugInfo, Debugger, Rustdoc};
-use crate::common::{CompareMode, FailMode, PassMode};
-use crate::common::{Config, TestPaths};
-use crate::common::{CoverageMap, CoverageRun, Pretty, RunPassValgrind};
-use crate::common::{UI_RUN_STDERR, UI_RUN_STDOUT};
-use crate::compute_diff::{write_diff, write_filtered_diff};
-use crate::errors::{self, Error, ErrorKind};
-use crate::header::TestProps;
-use crate::json;
-use crate::read2::{read2_abbreviated, Truncated};
-use crate::util::{add_dylib_path, copy_dir_all, dylib_env_var, logv, static_regex, PathBufExt};
-use crate::ColorConfig;
-use colored::Colorize;
-use miropt_test_tools::{files_for_miropt_test, MiroptTest, MiroptTestFile};
-use regex::{Captures, Regex};
-use rustfix::{apply_suggestions, get_suggestions_from_json, Filter};
+use std::borrow::Cow;
 use std::collections::{HashMap, HashSet};
-use std::env;
 use std::ffi::{OsStr, OsString};
 use std::fs::{self, create_dir_all, File, OpenOptions};
 use std::hash::{DefaultHasher, Hash, Hasher};
 use std::io::prelude::*;
 use std::io::{self, BufReader};
-use std::iter;
 use std::path::{Path, PathBuf};
 use std::process::{Child, Command, ExitStatus, Output, Stdio};
-use std::str;
 use std::sync::Arc;
+use std::{env, iter, str};
 
 use anyhow::Context;
+use colored::Colorize;
 use glob::glob;
+use miropt_test_tools::{files_for_miropt_test, MiroptTest, MiroptTestFile};
+use regex::{Captures, Regex};
+use rustfix::{apply_suggestions, get_suggestions_from_json, Filter};
 use tracing::*;
 
-use crate::extract_gdb_version;
-use crate::is_android_gdb_target;
+use crate::common::{
+    expected_output_path, incremental_dir, output_base_dir, output_base_name,
+    output_testname_unique, Assembly, Codegen, CodegenUnits, CompareMode, Config, CoverageMap,
+    CoverageRun, Crashes, DebugInfo, Debugger, FailMode, Incremental, JsDocTest, MirOpt, PassMode,
+    Pretty, RunMake, RunPassValgrind, Rustdoc, RustdocJson, TestPaths, Ui, UI_EXTENSIONS, UI_FIXED,
+    UI_RUN_STDERR, UI_RUN_STDOUT, UI_STDERR, UI_STDOUT, UI_SVG, UI_WINDOWS_SVG,
+};
+use crate::compute_diff::{write_diff, write_filtered_diff};
+use crate::errors::{self, Error, ErrorKind};
+use crate::header::TestProps;
+use crate::read2::{read2_abbreviated, Truncated};
+use crate::util::{add_dylib_path, copy_dir_all, dylib_env_var, logv, static_regex, PathBufExt};
+use crate::{extract_gdb_version, is_android_gdb_target, json, ColorConfig};
 
 mod coverage;
 mod debugger;
@@ -731,7 +724,7 @@ impl<'test> TestCx<'test> {
         self.maybe_add_external_args(&mut rustc, &self.config.target_rustcflags);
         rustc.args(&self.props.compile_flags);
 
-        self.compose_and_run_compiler(rustc, Some(src))
+        self.compose_and_run_compiler(rustc, Some(src), self.testpaths)
     }
 
     fn run_debuginfo_test(&self) {
@@ -1587,13 +1580,15 @@ impl<'test> TestCx<'test> {
             passes,
         );
 
-        self.compose_and_run_compiler(rustc, None)
+        self.compose_and_run_compiler(rustc, None, self.testpaths)
     }
 
-    fn document(&self, out_dir: &Path) -> ProcRes {
+    /// `root_out_dir` and `root_testpaths` refer to the parameters of the actual test being run.
+    /// Auxiliaries, no matter how deep, have the same root_out_dir and root_testpaths.
+    fn document(&self, root_out_dir: &Path, root_testpaths: &TestPaths) -> ProcRes {
         if self.props.build_aux_docs {
             for rel_ab in &self.props.aux_builds {
-                let aux_testpaths = self.compute_aux_test_paths(&self.testpaths, rel_ab);
+                let aux_testpaths = self.compute_aux_test_paths(root_testpaths, rel_ab);
                 let aux_props =
                     self.props.from_aux_file(&aux_testpaths.file, self.revision, self.config);
                 let aux_cx = TestCx {
@@ -1604,7 +1599,9 @@ impl<'test> TestCx<'test> {
                 };
                 // Create the directory for the stdout/stderr files.
                 create_dir_all(aux_cx.output_base_dir()).unwrap();
-                let auxres = aux_cx.document(out_dir);
+                // use root_testpaths here, because aux-builds should have the
+                // same --out-dir and auxiliary directory.
+                let auxres = aux_cx.document(&root_out_dir, root_testpaths);
                 if !auxres.status.success() {
                     return auxres;
                 }
@@ -1614,21 +1611,40 @@ impl<'test> TestCx<'test> {
         let aux_dir = self.aux_output_dir_name();
 
         let rustdoc_path = self.config.rustdoc_path.as_ref().expect("--rustdoc-path not passed");
-        let mut rustdoc = Command::new(rustdoc_path);
 
+        // actual --out-dir given to the auxiliary or test, as opposed to the root out dir for the entire
+        // test
+        let out_dir: Cow<'_, Path> = if self.props.unique_doc_out_dir {
+            let file_name = self.testpaths.file.file_stem().expect("file name should not be empty");
+            let out_dir = PathBuf::from_iter([
+                root_out_dir,
+                Path::new("docs"),
+                Path::new(file_name),
+                Path::new("doc"),
+            ]);
+            create_dir_all(&out_dir).unwrap();
+            Cow::Owned(out_dir)
+        } else {
+            Cow::Borrowed(root_out_dir)
+        };
+
+        let mut rustdoc = Command::new(rustdoc_path);
+        let current_dir = output_base_dir(self.config, root_testpaths, self.safe_revision());
+        rustdoc.current_dir(current_dir);
         rustdoc
             .arg("-L")
             .arg(self.config.run_lib_path.to_str().unwrap())
             .arg("-L")
             .arg(aux_dir)
             .arg("-o")
-            .arg(out_dir)
+            .arg(out_dir.as_ref())
             .arg("--deny")
             .arg("warnings")
             .arg(&self.testpaths.file)
             .arg("-A")
             .arg("internal_features")
-            .args(&self.props.compile_flags);
+            .args(&self.props.compile_flags)
+            .args(&self.props.doc_flags);
 
         if self.config.mode == RustdocJson {
             rustdoc.arg("--output-format").arg("json").arg("-Zunstable-options");
@@ -1638,7 +1654,7 @@ impl<'test> TestCx<'test> {
             rustdoc.arg(format!("-Clinker={}", linker));
         }
 
-        self.compose_and_run_compiler(rustdoc, None)
+        self.compose_and_run_compiler(rustdoc, None, root_testpaths)
     }
 
     fn exec_compiled_test(&self) -> ProcRes {
@@ -1836,9 +1852,16 @@ impl<'test> TestCx<'test> {
         }
     }
 
-    fn compose_and_run_compiler(&self, mut rustc: Command, input: Option<String>) -> ProcRes {
+    /// `root_testpaths` refers to the path of the original test.
+    /// the auxiliary and the test with an aux-build have the same `root_testpaths`.
+    fn compose_and_run_compiler(
+        &self,
+        mut rustc: Command,
+        input: Option<String>,
+        root_testpaths: &TestPaths,
+    ) -> ProcRes {
         let aux_dir = self.aux_output_dir();
-        self.build_all_auxiliary(&self.testpaths, &aux_dir, &mut rustc);
+        self.build_all_auxiliary(root_testpaths, &aux_dir, &mut rustc);
 
         rustc.envs(self.props.rustc_env.clone());
         self.props.unset_rustc_env.iter().fold(&mut rustc, Command::env_remove);
@@ -2553,7 +2576,7 @@ impl<'test> TestCx<'test> {
             Vec::new(),
         );
 
-        let proc_res = self.compose_and_run_compiler(rustc, None);
+        let proc_res = self.compose_and_run_compiler(rustc, None, self.testpaths);
         let output_path = self.get_filecheck_file("ll");
         (proc_res, output_path)
     }
@@ -2589,7 +2612,7 @@ impl<'test> TestCx<'test> {
             Vec::new(),
         );
 
-        let proc_res = self.compose_and_run_compiler(rustc, None);
+        let proc_res = self.compose_and_run_compiler(rustc, None, self.testpaths);
         let output_path = self.get_filecheck_file("s");
         (proc_res, output_path)
     }
@@ -2672,7 +2695,7 @@ impl<'test> TestCx<'test> {
         let out_dir = self.output_base_dir();
         remove_and_create_dir_all(&out_dir);
 
-        let proc_res = self.document(&out_dir);
+        let proc_res = self.document(&out_dir, &self.testpaths);
         if !proc_res.status.success() {
             self.fatal_proc_rec("rustdoc failed!", &proc_res);
         }
@@ -2731,7 +2754,7 @@ impl<'test> TestCx<'test> {
         let aux_dir = new_rustdoc.aux_output_dir();
         new_rustdoc.build_all_auxiliary(&new_rustdoc.testpaths, &aux_dir, &mut rustc);
 
-        let proc_res = new_rustdoc.document(&compare_dir);
+        let proc_res = new_rustdoc.document(&compare_dir, &new_rustdoc.testpaths);
         if !proc_res.status.success() {
             eprintln!("failed to run nightly rustdoc");
             return;
@@ -2739,6 +2762,7 @@ impl<'test> TestCx<'test> {
 
         #[rustfmt::skip]
         let tidy_args = [
+            "--new-blocklevel-tags", "rustdoc-search",
             "--indent", "yes",
             "--indent-spaces", "2",
             "--wrap", "0",
@@ -2854,7 +2878,7 @@ impl<'test> TestCx<'test> {
         let out_dir = self.output_base_dir();
         remove_and_create_dir_all(&out_dir);
 
-        let proc_res = self.document(&out_dir);
+        let proc_res = self.document(&out_dir, &self.testpaths);
         if !proc_res.status.success() {
             self.fatal_proc_rec("rustdoc failed!", &proc_res);
         }
@@ -2930,31 +2954,24 @@ impl<'test> TestCx<'test> {
     fn check_rustdoc_test_option(&self, res: ProcRes) {
         let mut other_files = Vec::new();
         let mut files: HashMap<String, Vec<usize>> = HashMap::new();
-        let cwd = env::current_dir().unwrap();
-        files.insert(
-            self.testpaths
-                .file
-                .strip_prefix(&cwd)
-                .unwrap_or(&self.testpaths.file)
-                .to_str()
-                .unwrap()
-                .replace('\\', "/"),
-            self.get_lines(&self.testpaths.file, Some(&mut other_files)),
-        );
+        let normalized = fs::canonicalize(&self.testpaths.file).expect("failed to canonicalize");
+        let normalized = normalized.to_str().unwrap().replace('\\', "/");
+        files.insert(normalized, self.get_lines(&self.testpaths.file, Some(&mut other_files)));
         for other_file in other_files {
             let mut path = self.testpaths.file.clone();
             path.set_file_name(&format!("{}.rs", other_file));
-            files.insert(
-                path.strip_prefix(&cwd).unwrap_or(&path).to_str().unwrap().replace('\\', "/"),
-                self.get_lines(&path, None),
-            );
+            let path = fs::canonicalize(path).expect("failed to canonicalize");
+            let normalized = path.to_str().unwrap().replace('\\', "/");
+            files.insert(normalized, self.get_lines(&path, None));
         }
 
         let mut tested = 0;
         for _ in res.stdout.split('\n').filter(|s| s.starts_with("test ")).inspect(|s| {
             if let Some((left, right)) = s.split_once(" - ") {
                 let path = left.rsplit("test ").next().unwrap();
-                if let Some(ref mut v) = files.get_mut(&path.replace('\\', "/")) {
+                let path = fs::canonicalize(&path).expect("failed to canonicalize");
+                let path = path.to_str().unwrap().replace('\\', "/");
+                if let Some(ref mut v) = files.get_mut(&path) {
                     tested += 1;
                     let mut iter = right.split("(line ");
                     iter.next();
@@ -3010,11 +3027,17 @@ impl<'test> TestCx<'test> {
         const PREFIX: &str = "MONO_ITEM ";
         const CGU_MARKER: &str = "@@";
 
+        // Some MonoItems can contain {closure@/path/to/checkout/tests/codgen-units/test.rs}
+        // To prevent the current dir from leaking, we just replace the entire path to the test
+        // file with TEST_PATH.
         let actual: Vec<MonoItem> = proc_res
             .stdout
             .lines()
             .filter(|line| line.starts_with(PREFIX))
-            .map(|line| str_to_mono_item(line, true))
+            .map(|line| {
+                line.replace(&self.testpaths.file.display().to_string(), "TEST_PATH").to_string()
+            })
+            .map(|line| str_to_mono_item(&line, true))
             .collect();
 
         let expected: Vec<MonoItem> = errors::load_errors(&self.testpaths.file, None)
@@ -3712,15 +3735,14 @@ impl<'test> TestCx<'test> {
         }
 
         if self.config.bless {
-            cmd.env("RUSTC_BLESS_TEST", "--bless");
-            // Assume this option is active if the environment variable is "defined", with _any_ value.
-            // As an example, a `Makefile` can use this option by:
+            // If we're running in `--bless` mode, set an environment variable to tell
+            // `run_make_support` to bless snapshot files instead of checking them.
             //
-            //   ifdef RUSTC_BLESS_TEST
-            //       cp "$(TMPDIR)"/actual_something.ext expected_something.ext
-            //   else
-            //       $(DIFF) expected_something.ext "$(TMPDIR)"/actual_something.ext
-            //   endif
+            // The value is this test's source directory, because the support code
+            // will need that path in order to bless the _original_ snapshot files,
+            // not the copies in `rmake_out`.
+            // (See <https://github.com/rust-lang/rust/issues/129038>.)
+            cmd.env("RUSTC_BLESS_TEST", &self.testpaths.file);
         }
 
         if self.config.target.contains("msvc") && !self.config.cc.is_empty() {
@@ -3786,7 +3808,7 @@ impl<'test> TestCx<'test> {
         if let Some(nodejs) = &self.config.nodejs {
             let out_dir = self.output_base_dir();
 
-            self.document(&out_dir);
+            self.document(&out_dir, &self.testpaths);
 
             let root = self.config.find_rust_src_root().unwrap();
             let file_stem =
@@ -4102,7 +4124,7 @@ impl<'test> TestCx<'test> {
                 rustc.arg(crate_name);
             }
 
-            let res = self.compose_and_run_compiler(rustc, None);
+            let res = self.compose_and_run_compiler(rustc, None, self.testpaths);
             if !res.status.success() {
                 self.fatal_proc_rec("failed to compile fixed code", &res);
             }
diff --git a/src/tools/compiletest/src/runtest/coverage.rs b/src/tools/compiletest/src/runtest/coverage.rs
index 6ee147da5a9..05191a15980 100644
--- a/src/tools/compiletest/src/runtest/coverage.rs
+++ b/src/tools/compiletest/src/runtest/coverage.rs
@@ -191,7 +191,7 @@ impl<'test> TestCx<'test> {
 
         rustdoc_cmd.arg(&self.testpaths.file);
 
-        let proc_res = self.compose_and_run_compiler(rustdoc_cmd, None);
+        let proc_res = self.compose_and_run_compiler(rustdoc_cmd, None, self.testpaths);
         if !proc_res.status.success() {
             self.fatal_proc_rec("rustdoc --test failed!", &proc_res)
         }
diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs
index ed6cc97a8ab..985fe6381e8 100644
--- a/src/tools/compiletest/src/runtest/debugger.rs
+++ b/src/tools/compiletest/src/runtest/debugger.rs
@@ -1,12 +1,12 @@
-use crate::common::Config;
-use crate::header::line_directive;
-use crate::runtest::ProcRes;
-
 use std::fmt::Write;
 use std::fs::File;
 use std::io::{BufRead, BufReader};
 use std::path::{Path, PathBuf};
 
+use crate::common::Config;
+use crate::header::line_directive;
+use crate::runtest::ProcRes;
+
 /// Representation of information to invoke a debugger and check its output
 pub(super) struct DebuggerCommands {
     /// Commands for the debuuger
diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs
index cdec49a51d7..bff02f1db9f 100644
--- a/src/tools/compiletest/src/util.rs
+++ b/src/tools/compiletest/src/util.rs
@@ -1,4 +1,3 @@
-use crate::common::Config;
 use std::env;
 use std::ffi::OsStr;
 use std::path::{Path, PathBuf};
@@ -6,6 +5,8 @@ use std::process::Command;
 
 use tracing::*;
 
+use crate::common::Config;
+
 #[cfg(test)]
 mod tests;
 
diff --git a/src/tools/coverage-dump/src/covfun.rs b/src/tools/coverage-dump/src/covfun.rs
index b308c8de14f..4729b327de5 100644
--- a/src/tools/coverage-dump/src/covfun.rs
+++ b/src/tools/coverage-dump/src/covfun.rs
@@ -1,10 +1,12 @@
-use crate::parser::{unescape_llvm_string_contents, Parser};
-use anyhow::{anyhow, Context};
-use regex::Regex;
 use std::collections::HashMap;
 use std::fmt::{self, Debug, Write as _};
 use std::sync::OnceLock;
 
+use anyhow::{anyhow, Context};
+use regex::Regex;
+
+use crate::parser::{unescape_llvm_string_contents, Parser};
+
 pub(crate) fn dump_covfun_mappings(
     llvm_ir: &str,
     function_names: &HashMap<u64, String>,
diff --git a/src/tools/coverage-dump/src/parser.rs b/src/tools/coverage-dump/src/parser.rs
index eefac1a4f94..0bd4abdae3e 100644
--- a/src/tools/coverage-dump/src/parser.rs
+++ b/src/tools/coverage-dump/src/parser.rs
@@ -1,9 +1,10 @@
 #[cfg(test)]
 mod tests;
 
+use std::sync::OnceLock;
+
 use anyhow::ensure;
 use regex::bytes;
-use std::sync::OnceLock;
 
 /// Given the raw contents of a string literal in LLVM IR assembly, decodes any
 /// backslash escapes and returns a vector containing the resulting byte string.
diff --git a/src/tools/coverage-dump/src/prf_names.rs b/src/tools/coverage-dump/src/prf_names.rs
index d3f7b819e48..c5f9c4ce54c 100644
--- a/src/tools/coverage-dump/src/prf_names.rs
+++ b/src/tools/coverage-dump/src/prf_names.rs
@@ -1,9 +1,11 @@
-use crate::parser::{unescape_llvm_string_contents, Parser};
-use anyhow::{anyhow, ensure};
-use regex::Regex;
 use std::collections::HashMap;
 use std::sync::OnceLock;
 
+use anyhow::{anyhow, ensure};
+use regex::Regex;
+
+use crate::parser::{unescape_llvm_string_contents, Parser};
+
 /// Scans through the contents of an LLVM IR assembly file to find `__llvm_prf_names`
 /// entries, decodes them, and creates a table that maps name hash values to
 /// (demangled) function names.
diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs
index 2de2d959a95..53a26112911 100644
--- a/src/tools/error_index_generator/main.rs
+++ b/src/tools/error_index_generator/main.rs
@@ -5,18 +5,16 @@ extern crate rustc_log;
 extern crate rustc_session;
 
 extern crate rustc_errors;
-use rustc_errors::codes::DIAGNOSTICS;
-
 use std::env;
 use std::error::Error;
 use std::fs::{self, File};
 use std::io::Write;
-use std::path::Path;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
 use std::str::FromStr;
 
 use mdbook::book::{parse_summary, BookItem, Chapter};
 use mdbook::{Config, MDBook};
+use rustc_errors::codes::DIAGNOSTICS;
 
 enum OutputFormat {
     HTML,
diff --git a/src/tools/generate-copyright/Cargo.toml b/src/tools/generate-copyright/Cargo.toml
index 899ef0f8a6c..404101abd41 100644
--- a/src/tools/generate-copyright/Cargo.toml
+++ b/src/tools/generate-copyright/Cargo.toml
@@ -2,10 +2,14 @@
 name = "generate-copyright"
 version = "0.1.0"
 edition = "2021"
+description = "Produces a manifest of all the copyrighted materials in the Rust Toolchain"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
 anyhow = "1.0.65"
+cargo_metadata = "0.18.1"
+rinja = "0.3.0"
 serde = { version = "1.0.147", features = ["derive"] }
 serde_json = "1.0.85"
+thiserror = "1"
diff --git a/src/tools/generate-copyright/src/cargo_metadata.rs b/src/tools/generate-copyright/src/cargo_metadata.rs
new file mode 100644
index 00000000000..c85e4aa371a
--- /dev/null
+++ b/src/tools/generate-copyright/src/cargo_metadata.rs
@@ -0,0 +1,191 @@
+//! Gets metadata about a workspace from Cargo
+
+use std::collections::BTreeMap;
+use std::ffi::OsStr;
+use std::path::{Path, PathBuf};
+
+/// Describes how this module can fail
+#[derive(Debug, thiserror::Error)]
+pub enum Error {
+    #[error("I/O Error: {0:?}")]
+    Io(#[from] std::io::Error),
+    #[error("Failed get output from cargo-metadata: {0:?}")]
+    GettingMetadata(#[from] cargo_metadata::Error),
+    #[error("Failed to run cargo vendor: {0:?}")]
+    LaunchingVendor(std::io::Error),
+    #[error("Failed to complete cargo vendor")]
+    RunningVendor,
+    #[error("Bad path {0:?} whilst scraping files")]
+    Scraping(PathBuf),
+}
+
+/// Uniquely describes a package on crates.io
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub struct Package {
+    /// The name of the package
+    pub name: String,
+    /// The version number
+    pub version: String,
+}
+
+/// Extra data about a package
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub struct PackageMetadata {
+    /// The license it is under
+    pub license: String,
+    /// The list of authors from the package metadata
+    pub authors: Vec<String>,
+    /// A list of important files from the package, with their contents.
+    ///
+    /// This includes *COPYRIGHT*, *NOTICE*, *AUTHOR*, *LICENSE*, and *LICENCE* files, case-insensitive.
+    pub notices: BTreeMap<String, String>,
+    /// If this is true, this dep is in the Rust Standard Library
+    pub is_in_libstd: Option<bool>,
+}
+
+/// Use `cargo metadata` and `cargo vendor` to get a list of dependencies and their license data.
+///
+/// This will involve running `cargo vendor` into `${BUILD}/vendor` so we can
+/// grab the license files.
+///
+/// Any dependency with a path beginning with `root_path` is ignored, as we
+/// assume `reuse` has covered it already.
+pub fn get_metadata_and_notices(
+    cargo: &Path,
+    dest: &Path,
+    root_path: &Path,
+    manifest_paths: &[&Path],
+) -> Result<BTreeMap<Package, PackageMetadata>, Error> {
+    let mut output = get_metadata(cargo, root_path, manifest_paths)?;
+
+    // Now do a cargo-vendor and grab everything
+    let vendor_path = dest.join("vendor");
+    println!("Vendoring deps into {}...", vendor_path.display());
+    run_cargo_vendor(cargo, &vendor_path, manifest_paths)?;
+
+    // Now for each dependency we found, go and grab any important looking files
+    for (package, metadata) in output.iter_mut() {
+        load_important_files(package, metadata, &vendor_path)?;
+    }
+
+    Ok(output)
+}
+
+/// Use `cargo metadata` to get a list of dependencies and their license data.
+///
+/// Any dependency with a path beginning with `root_path` is ignored, as we
+/// assume `reuse` has covered it already.
+pub fn get_metadata(
+    cargo: &Path,
+    root_path: &Path,
+    manifest_paths: &[&Path],
+) -> Result<BTreeMap<Package, PackageMetadata>, Error> {
+    let mut output = BTreeMap::new();
+    // Look at the metadata for each manifest
+    for manifest_path in manifest_paths {
+        if manifest_path.file_name() != Some(OsStr::new("Cargo.toml")) {
+            panic!("cargo_manifest::get requires a path to a Cargo.toml file");
+        }
+        let metadata = cargo_metadata::MetadataCommand::new()
+            .cargo_path(cargo)
+            .env("RUSTC_BOOTSTRAP", "1")
+            .manifest_path(manifest_path)
+            .exec()?;
+        for package in metadata.packages {
+            let manifest_path = package.manifest_path.as_path();
+            if manifest_path.starts_with(root_path) {
+                // it's an in-tree dependency and reuse covers it
+                continue;
+            }
+            // otherwise it's an out-of-tree dependency
+            let package_id = Package { name: package.name, version: package.version.to_string() };
+            output.insert(
+                package_id,
+                PackageMetadata {
+                    license: package.license.unwrap_or_else(|| String::from("Unspecified")),
+                    authors: package.authors,
+                    notices: BTreeMap::new(),
+                    is_in_libstd: None,
+                },
+            );
+        }
+    }
+
+    Ok(output)
+}
+
+/// Run cargo-vendor, fetching into the given dir
+fn run_cargo_vendor(cargo: &Path, dest: &Path, manifest_paths: &[&Path]) -> Result<(), Error> {
+    let mut vendor_command = std::process::Command::new(cargo);
+    vendor_command.env("RUSTC_BOOTSTRAP", "1");
+    vendor_command.arg("vendor");
+    vendor_command.arg("--quiet");
+    vendor_command.arg("--versioned-dirs");
+    for manifest_path in manifest_paths {
+        vendor_command.arg("-s");
+        vendor_command.arg(manifest_path);
+    }
+    vendor_command.arg(dest);
+
+    let vendor_status = vendor_command.status().map_err(Error::LaunchingVendor)?;
+
+    if !vendor_status.success() {
+        return Err(Error::RunningVendor);
+    }
+
+    Ok(())
+}
+
+/// Add important files off disk into this dependency.
+///
+/// Maybe one-day Cargo.toml will contain enough information that we don't need
+/// to do this manual scraping.
+fn load_important_files(
+    package: &Package,
+    dep: &mut PackageMetadata,
+    vendor_root: &Path,
+) -> Result<(), Error> {
+    let name_version = format!("{}-{}", package.name, package.version);
+    println!("Scraping notices for {}...", name_version);
+    let dep_vendor_path = vendor_root.join(name_version);
+    for entry in std::fs::read_dir(dep_vendor_path)? {
+        let entry = entry?;
+        let metadata = entry.metadata()?;
+        let path = entry.path();
+        let Some(filename) = path.file_name() else {
+            return Err(Error::Scraping(path));
+        };
+        let lc_filename = filename.to_ascii_lowercase();
+        let lc_filename_str = lc_filename.to_string_lossy();
+        let mut keep = false;
+        for m in ["copyright", "licence", "license", "author", "notice"] {
+            if lc_filename_str.contains(m) {
+                keep = true;
+                break;
+            }
+        }
+        if keep {
+            if metadata.is_dir() {
+                for inner_entry in std::fs::read_dir(entry.path())? {
+                    let inner_entry = inner_entry?;
+                    if inner_entry.metadata()?.is_file() {
+                        let inner_filename = inner_entry.file_name();
+                        let inner_filename_str = inner_filename.to_string_lossy();
+                        let qualified_filename =
+                            format!("{}/{}", lc_filename_str, inner_filename_str);
+                        println!("Scraping {}", qualified_filename);
+                        dep.notices.insert(
+                            qualified_filename.to_string(),
+                            std::fs::read_to_string(inner_entry.path())?,
+                        );
+                    }
+                }
+            } else if metadata.is_file() {
+                let filename = filename.to_string_lossy();
+                println!("Scraping {}", filename);
+                dep.notices.insert(filename.to_string(), std::fs::read_to_string(path)?);
+            }
+        }
+    }
+    Ok(())
+}
diff --git a/src/tools/generate-copyright/src/main.rs b/src/tools/generate-copyright/src/main.rs
index d91b258162e..afa75d0d671 100644
--- a/src/tools/generate-copyright/src/main.rs
+++ b/src/tools/generate-copyright/src/main.rs
@@ -1,78 +1,70 @@
+use std::collections::BTreeMap;
+use std::path::{Path, PathBuf};
+
 use anyhow::Error;
-use std::io::Write;
-use std::path::PathBuf;
+use rinja::Template;
+
+mod cargo_metadata;
+
+#[derive(Template)]
+#[template(path = "COPYRIGHT.html")]
+struct CopyrightTemplate {
+    in_tree: Node,
+    dependencies: BTreeMap<cargo_metadata::Package, cargo_metadata::PackageMetadata>,
+}
 
+/// The entry point to the binary.
+///
+/// You should probably let `bootstrap` execute this program instead of running it directly.
+///
+/// Run `x.py run generate-copyright`
 fn main() -> Result<(), Error> {
-    let dest = env_path("DEST")?;
+    let dest_file = env_path("DEST")?;
+    let out_dir = env_path("OUT_DIR")?;
+    let cargo = env_path("CARGO")?;
     let license_metadata = env_path("LICENSE_METADATA")?;
 
-    let metadata: Metadata = serde_json::from_slice(&std::fs::read(&license_metadata)?)?;
+    let collected_tree_metadata: Metadata =
+        serde_json::from_slice(&std::fs::read(&license_metadata)?)?;
 
-    let mut buffer = Vec::new();
-    render_recursive(&metadata.files, &mut buffer, 0)?;
+    let root_path = std::path::absolute(".")?;
+    let workspace_paths = [
+        Path::new("./Cargo.toml"),
+        Path::new("./src/tools/cargo/Cargo.toml"),
+        Path::new("./library/Cargo.toml"),
+    ];
+    let mut collected_cargo_metadata =
+        cargo_metadata::get_metadata_and_notices(&cargo, &out_dir, &root_path, &workspace_paths)?;
 
-    std::fs::write(&dest, &buffer)?;
-
-    Ok(())
-}
+    let stdlib_set =
+        cargo_metadata::get_metadata(&cargo, &root_path, &[Path::new("./library/std/Cargo.toml")])?;
 
-fn render_recursive(node: &Node, buffer: &mut Vec<u8>, depth: usize) -> Result<(), Error> {
-    let prefix = std::iter::repeat("> ").take(depth + 1).collect::<String>();
-
-    match node {
-        Node::Root { children } => {
-            for child in children {
-                render_recursive(child, buffer, depth)?;
-            }
-        }
-        Node::Directory { name, children, license } => {
-            render_license(&prefix, std::iter::once(name), license.as_ref(), buffer)?;
-            if !children.is_empty() {
-                writeln!(buffer, "{prefix}")?;
-                writeln!(buffer, "{prefix}*Exceptions:*")?;
-                for child in children {
-                    writeln!(buffer, "{prefix}")?;
-                    render_recursive(child, buffer, depth + 1)?;
-                }
-            }
-        }
-        Node::Group { files, directories, license } => {
-            render_license(&prefix, directories.iter().chain(files.iter()), Some(license), buffer)?;
-        }
-        Node::File { name, license } => {
-            render_license(&prefix, std::iter::once(name), Some(license), buffer)?;
-        }
+    for (key, value) in collected_cargo_metadata.iter_mut() {
+        value.is_in_libstd = Some(stdlib_set.contains_key(key));
     }
 
-    Ok(())
-}
+    let template = CopyrightTemplate {
+        in_tree: collected_tree_metadata.files,
+        dependencies: collected_cargo_metadata,
+    };
 
-fn render_license<'a>(
-    prefix: &str,
-    names: impl Iterator<Item = &'a String>,
-    license: Option<&License>,
-    buffer: &mut Vec<u8>,
-) -> Result<(), Error> {
-    for name in names {
-        writeln!(buffer, "{prefix}**`{name}`**  ")?;
-    }
-    if let Some(license) = license {
-        writeln!(buffer, "{prefix}License: `{}`", license.spdx)?;
-        for copyright in license.copyright.iter() {
-            writeln!(buffer, "{prefix}Copyright: {copyright}")?;
-        }
-    }
+    let output = template.render()?;
+
+    std::fs::write(&dest_file, output)?;
 
     Ok(())
 }
 
+/// Describes a tree of metadata for our filesystem tree
 #[derive(serde::Deserialize)]
 struct Metadata {
     files: Node,
 }
 
-#[derive(serde::Deserialize)]
+/// Describes one node in our metadata tree
+#[derive(serde::Deserialize, rinja::Template)]
 #[serde(rename_all = "kebab-case", tag = "type")]
+#[template(path = "Node.html")]
 pub(crate) enum Node {
     Root { children: Vec<Node> },
     Directory { name: String, children: Vec<Node>, license: Option<License> },
@@ -80,12 +72,14 @@ pub(crate) enum Node {
     Group { files: Vec<String>, directories: Vec<String>, license: License },
 }
 
+/// A License has an SPDX license name and a list of copyright holders.
 #[derive(serde::Deserialize)]
 struct License {
     spdx: String,
     copyright: Vec<String>,
 }
 
+/// Grab an environment variable as a PathBuf, or fail nicely.
 fn env_path(var: &str) -> Result<PathBuf, Error> {
     if let Some(var) = std::env::var_os(var) {
         Ok(var.into())
diff --git a/src/tools/generate-copyright/templates/COPYRIGHT.html b/src/tools/generate-copyright/templates/COPYRIGHT.html
new file mode 100644
index 00000000000..ccb177a54d4
--- /dev/null
+++ b/src/tools/generate-copyright/templates/COPYRIGHT.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="UTF-8">
+    <title>Copyright notices for The Rust Toolchain</title>
+</head>
+<body>
+
+<h1>Copyright notices for The Rust Toolchain</h1>
+
+<p>This file describes the copyright and licensing information for the source
+code within The Rust Project git tree, and the third-party dependencies used
+when building the Rust toolchain (including the Rust Standard Library).</p>
+
+<h2>Table of Contents</h2>
+<ul>
+    <li><a href="#in-tree-files">In-tree files</a></li>
+    <li><a href="#out-of-tree-dependencies">Out-of-tree dependencies</a></li>
+</ul>
+
+<h2 id="in-tree-files">In-tree files</h2>
+
+<p>The following licenses cover the in-tree source files that were used in this
+release:</p>
+
+{{ in_tree|safe }}
+
+<h2 id="out-of-tree-dependencies">Out-of-tree dependencies</h2>
+
+<p>The following licenses cover the out-of-tree crates that were used in this
+release:</p>
+
+{% for (key, value) in dependencies %}
+    <h3>📦 {{key.name}}-{{key.version}}</h3>
+    <p><b>URL:</b> <a href="https://crates.io/crates/{{ key.name }}/{{ key.version }}">https://crates.io/crates/{{ key.name }}/{{ key.version }}</a></p>
+    <p><b>In libstd:</b> {% if value.is_in_libstd.unwrap() %} Yes {% else %} No {% endif %}</p>
+    <p><b>Authors:</b> {{ value.authors|join(", ") }}</p>
+    <p><b>License:</b> {{ value.license }}</p>
+    {% let len = value.notices.len() %}
+    {% if len > 0 %}
+        <p><b>Notices:</b>
+        {% for (notice_name, notice_text) in value.notices %}
+            <details>
+                <summary><code>{{ notice_name }}</code></summary>
+                <pre>
+{{ notice_text }}
+                </pre>
+            </details>
+        {% endfor %}
+        </p>
+    {% endif %}
+{% endfor %}
+</body>
+</html>
\ No newline at end of file
diff --git a/src/tools/generate-copyright/templates/Node.html b/src/tools/generate-copyright/templates/Node.html
new file mode 100644
index 00000000000..a71a1bf3b73
--- /dev/null
+++ b/src/tools/generate-copyright/templates/Node.html
@@ -0,0 +1,71 @@
+{% match self %}
+
+{% when Node::Root { children } %}
+
+{% for child in children %}
+{{ child|safe }}
+{% endfor %}
+
+{% when Node::Directory { name, children, license } %}
+
+<div style="border:1px solid black; padding: 5px;">
+
+    <p>
+    <b>File/Directory:</b> <code>{{ name }}</code>
+    </p>
+
+    {% if let Some(license) = license %}
+
+    <p><b>License:</b> {{ license.spdx }}</p>
+    {% for copyright in license.copyright.iter() %}
+    <p><b>Copyright:</b> {{ copyright }}</p>
+    {% endfor %}
+
+    {% endif %}
+
+    {% if !children.is_empty() %}
+
+    <p><b>Exceptions:</b></p>
+    {% for child in children %}
+    {{ child|safe }}
+    {% endfor %}
+
+    {% endif %}
+
+</div>
+
+{% when Node::File { name, license } %}
+
+<div style="border:1px solid black; padding: 5px;">
+    <p>
+    <b>File/Directory:</b> <code>{{ name }}</code>
+    </p>
+
+    <p><b>License:</b> {{ license.spdx }}</p>
+    {% for copyright in license.copyright.iter() %}
+    <p><b>Copyright:</b> {{ copyright }}</p>
+    {% endfor %}
+</div>
+
+{% when Node::Group { files, directories, license } %}
+
+<div style="border:1px solid black; padding: 5px;">
+
+    <p>
+        <b>File/Directory:</b>
+        {% for name in files %}
+        <code>{{ name }}</code>
+        {% endfor %}
+        {% for name in directories %}
+        <code>{{ name }}</code>
+        {% endfor %}
+    </p>
+
+    <p><b>License:</b> {{ license.spdx }}</p>
+    {% for copyright in license.copyright.iter() %}
+    <p><b>Copyright:</b> {{ copyright }}</p>
+    {% endfor %}
+
+</div>
+
+{% endmatch %}
diff --git a/src/tools/generate-windows-sys/src/main.rs b/src/tools/generate-windows-sys/src/main.rs
index 90fce2b675a..fe1b1bd5ceb 100644
--- a/src/tools/generate-windows-sys/src/main.rs
+++ b/src/tools/generate-windows-sys/src/main.rs
@@ -1,8 +1,7 @@
-use std::env;
 use std::error::Error;
-use std::fs;
 use std::io::{Read, Seek, SeekFrom, Write};
 use std::path::PathBuf;
+use std::{env, fs};
 
 /// 32-bit ARM is not supported by Microsoft so ARM types are not generated.
 /// Therefore we need to inject a few types to make the bindings work.
diff --git a/src/tools/html-checker/main.rs b/src/tools/html-checker/main.rs
index e74f72608ef..ecfbb1955e7 100644
--- a/src/tools/html-checker/main.rs
+++ b/src/tools/html-checker/main.rs
@@ -1,8 +1,9 @@
-use rayon::iter::{ParallelBridge, ParallelIterator};
 use std::env;
 use std::path::Path;
 use std::process::{Command, Output};
 
+use rayon::iter::{ParallelBridge, ParallelIterator};
+
 fn check_html_file(file: &Path) -> usize {
     let to_mute = &[
         // "disabled" on <link> or "autocomplete" on <select> emit this warning
diff --git a/src/tools/jsondocck/src/cache.rs b/src/tools/jsondocck/src/cache.rs
index 5f72bd171a1..9f95f9fb408 100644
--- a/src/tools/jsondocck/src/cache.rs
+++ b/src/tools/jsondocck/src/cache.rs
@@ -1,9 +1,10 @@
-use crate::config::Config;
-use serde_json::Value;
 use std::collections::HashMap;
 use std::path::Path;
 
 use fs_err as fs;
+use serde_json::Value;
+
+use crate::config::Config;
 
 #[derive(Debug)]
 pub struct Cache {
diff --git a/src/tools/jsondocck/src/error.rs b/src/tools/jsondocck/src/error.rs
index 53b9af2874b..c4cd79a64fd 100644
--- a/src/tools/jsondocck/src/error.rs
+++ b/src/tools/jsondocck/src/error.rs
@@ -1,7 +1,8 @@
-use crate::Command;
 use std::error::Error;
 use std::fmt;
 
+use crate::Command;
+
 #[derive(Debug)]
 pub enum CkError {
     /// A check failed. File didn't exist or failed to match the command
diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs
index de94990b53e..b264405ac3e 100644
--- a/src/tools/jsondocck/src/main.rs
+++ b/src/tools/jsondocck/src/main.rs
@@ -1,10 +1,11 @@
-use jsonpath_lib::select;
-use regex::{Regex, RegexBuilder};
-use serde_json::Value;
 use std::borrow::Cow;
 use std::sync::OnceLock;
 use std::{env, fmt, fs};
 
+use jsonpath_lib::select;
+use regex::{Regex, RegexBuilder};
+use serde_json::Value;
+
 mod cache;
 mod config;
 mod error;
diff --git a/src/tools/jsondoclint/src/item_kind.rs b/src/tools/jsondoclint/src/item_kind.rs
index 525de03bbce..7d6ec475bad 100644
--- a/src/tools/jsondoclint/src/item_kind.rs
+++ b/src/tools/jsondoclint/src/item_kind.rs
@@ -13,7 +13,6 @@ pub(crate) enum Kind {
     Variant,
     Function,
     TypeAlias,
-    OpaqueTy,
     Constant,
     Trait,
     TraitAlias,
@@ -55,7 +54,6 @@ impl Kind {
 
             // FIXME(adotinthevoid): I'm not sure if these are correct
             Keyword => false,
-            OpaqueTy => false,
             ProcAttribute => false,
             ProcDerive => false,
 
@@ -99,7 +97,6 @@ impl Kind {
             Kind::Enum => false,
             Kind::Variant => false,
             Kind::TypeAlias => false,
-            Kind::OpaqueTy => false,
             Kind::Constant => false,
             Kind::Trait => false,
             Kind::TraitAlias => false,
@@ -149,7 +146,6 @@ impl Kind {
             ItemEnum::TraitAlias(_) => TraitAlias,
             ItemEnum::Impl(_) => Impl,
             ItemEnum::TypeAlias(_) => TypeAlias,
-            ItemEnum::OpaqueTy(_) => OpaqueTy,
             ItemEnum::Constant { .. } => Constant,
             ItemEnum::Static(_) => Static,
             ItemEnum::Macro(_) => Macro,
@@ -177,7 +173,6 @@ impl Kind {
             ItemKind::Keyword => Keyword,
             ItemKind::Macro => Macro,
             ItemKind::Module => Module,
-            ItemKind::OpaqueTy => OpaqueTy,
             ItemKind::Primitive => Primitive,
             ItemKind::ProcAttribute => ProcAttribute,
             ItemKind::ProcDerive => ProcDerive,
diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs
index ea1e573384b..0ffb96bef29 100644
--- a/src/tools/jsondoclint/src/validator.rs
+++ b/src/tools/jsondoclint/src/validator.rs
@@ -3,13 +3,14 @@ use std::hash::Hash;
 
 use rustdoc_json_types::{
     Constant, Crate, DynTrait, Enum, FnDecl, Function, FunctionPointer, GenericArg, GenericArgs,
-    GenericBound, GenericParamDef, Generics, Id, Impl, Import, ItemEnum, ItemSummary, Module,
-    OpaqueTy, Path, Primitive, ProcMacro, Static, Struct, StructKind, Term, Trait, TraitAlias,
-    Type, TypeAlias, TypeBinding, TypeBindingKind, Union, Variant, VariantKind, WherePredicate,
+    GenericBound, GenericParamDef, Generics, Id, Impl, Import, ItemEnum, ItemSummary, Module, Path,
+    Primitive, ProcMacro, Static, Struct, StructKind, Term, Trait, TraitAlias, Type, TypeAlias,
+    TypeBinding, TypeBindingKind, Union, Variant, VariantKind, WherePredicate,
 };
 use serde_json::Value;
 
-use crate::{item_kind::Kind, json_find, Error, ErrorKind};
+use crate::item_kind::Kind;
+use crate::{json_find, Error, ErrorKind};
 
 // This is a rustc implementation detail that we rely on here
 const LOCAL_CRATE_ID: u32 = 0;
@@ -100,7 +101,6 @@ impl<'a> Validator<'a> {
                 ItemEnum::TraitAlias(x) => self.check_trait_alias(x),
                 ItemEnum::Impl(x) => self.check_impl(x, id),
                 ItemEnum::TypeAlias(x) => self.check_type_alias(x),
-                ItemEnum::OpaqueTy(x) => self.check_opaque_ty(x),
                 ItemEnum::Constant { type_, const_ } => {
                     self.check_type(type_);
                     self.check_constant(const_);
@@ -229,11 +229,6 @@ impl<'a> Validator<'a> {
         self.check_type(&x.type_);
     }
 
-    fn check_opaque_ty(&mut self, x: &'a OpaqueTy) {
-        x.bounds.iter().for_each(|b| self.check_generic_bound(b));
-        self.check_generics(&x.generics);
-    }
-
     fn check_constant(&mut self, _x: &'a Constant) {
         // nop
     }
diff --git a/src/tools/jsondoclint/src/validator/tests.rs b/src/tools/jsondoclint/src/validator/tests.rs
index ba0fe11ea26..f28702de06d 100644
--- a/src/tools/jsondoclint/src/validator/tests.rs
+++ b/src/tools/jsondoclint/src/validator/tests.rs
@@ -1,9 +1,8 @@
 use rustc_hash::FxHashMap;
 use rustdoc_json_types::{Item, ItemKind, Visibility, FORMAT_VERSION};
 
-use crate::json_find::SelectorPart;
-
 use super::*;
+use crate::json_find::SelectorPart;
 
 #[track_caller]
 fn check(krate: &Crate, errs: &[Error]) {
diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs
index 72ae3ed26e8..72448c1180a 100644
--- a/src/tools/linkchecker/main.rs
+++ b/src/tools/linkchecker/main.rs
@@ -14,18 +14,18 @@
 //! A few exceptions are allowed as there's known bugs in rustdoc, but this
 //! should catch the majority of "broken link" cases.
 
-use html5ever::tendril::ByteTendril;
-use html5ever::tokenizer::{
-    BufferQueue, TagToken, Token, TokenSink, TokenSinkResult, Tokenizer, TokenizerOpts,
-};
 use std::cell::RefCell;
 use std::collections::{HashMap, HashSet};
-use std::env;
-use std::fs;
 use std::io::ErrorKind;
 use std::path::{Component, Path, PathBuf};
 use std::rc::Rc;
 use std::time::Instant;
+use std::{env, fs};
+
+use html5ever::tendril::ByteTendril;
+use html5ever::tokenizer::{
+    BufferQueue, TagToken, Token, TokenSink, TokenSinkResult, Tokenizer, TokenizerOpts,
+};
 
 // Add linkcheck exceptions here
 // If at all possible you should use intra-doc links to avoid linkcheck issues. These
diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs
index 0d827ab2e72..78d4f87ed0d 100644
--- a/src/tools/lint-docs/src/groups.rs
+++ b/src/tools/lint-docs/src/groups.rs
@@ -1,10 +1,11 @@
-use crate::{Lint, LintExtractor};
 use std::collections::{BTreeMap, BTreeSet};
 use std::error::Error;
 use std::fmt::Write;
 use std::fs;
 use std::process::Command;
 
+use crate::{Lint, LintExtractor};
+
 /// Descriptions of rustc lint groups.
 static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[
     ("unused", "Lints that detect things being declared but not used, or excess syntax"),
diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs
index 48e2dd09876..e0aef13ca79 100644
--- a/src/tools/lint-docs/src/lib.rs
+++ b/src/tools/lint-docs/src/lib.rs
@@ -3,6 +3,7 @@ use std::fmt::Write;
 use std::fs;
 use std::path::{Path, PathBuf};
 use std::process::Command;
+
 use walkdir::WalkDir;
 
 mod groups;
diff --git a/src/tools/lld-wrapper/src/main.rs b/src/tools/lld-wrapper/src/main.rs
index 79e279a8614..2f756ae3022 100644
--- a/src/tools/lld-wrapper/src/main.rs
+++ b/src/tools/lld-wrapper/src/main.rs
@@ -11,7 +11,8 @@
 //! obtained from the wrapper's name as the first two arguments.
 //! On Windows it spawns a `..\rust-lld.exe` child process.
 
-use std::env::{self, consts::EXE_SUFFIX};
+use std::env::consts::EXE_SUFFIX;
+use std::env::{self};
 use std::fmt::Display;
 use std::path::{Path, PathBuf};
 use std::process;
diff --git a/src/tools/llvm-bitcode-linker/src/bin/llvm-bitcode-linker.rs b/src/tools/llvm-bitcode-linker/src/bin/llvm-bitcode-linker.rs
index a92af71a36e..fdbf6171c53 100644
--- a/src/tools/llvm-bitcode-linker/src/bin/llvm-bitcode-linker.rs
+++ b/src/tools/llvm-bitcode-linker/src/bin/llvm-bitcode-linker.rs
@@ -1,7 +1,6 @@
 use std::path::PathBuf;
 
 use clap::Parser;
-
 use llvm_bitcode_linker::{Optimization, Session, Target};
 
 #[derive(Debug, Parser)]
diff --git a/src/tools/llvm-bitcode-linker/src/linker.rs b/src/tools/llvm-bitcode-linker/src/linker.rs
index 40572f22342..9f579d10094 100644
--- a/src/tools/llvm-bitcode-linker/src/linker.rs
+++ b/src/tools/llvm-bitcode-linker/src/linker.rs
@@ -2,8 +2,7 @@ use std::path::PathBuf;
 
 use anyhow::Context;
 
-use crate::Optimization;
-use crate::Target;
+use crate::{Optimization, Target};
 
 #[derive(Debug)]
 pub struct Session {
diff --git a/src/tools/llvm-bitcode-linker/src/opt.rs b/src/tools/llvm-bitcode-linker/src/opt.rs
index 93f0ec7e2d6..12692c4cbb4 100644
--- a/src/tools/llvm-bitcode-linker/src/opt.rs
+++ b/src/tools/llvm-bitcode-linker/src/opt.rs
@@ -1,5 +1,4 @@
-use std::fmt::Display;
-use std::fmt::Formatter;
+use std::fmt::{Display, Formatter};
 
 #[derive(Debug, Clone, Copy, Default, Hash, Eq, PartialEq, clap::ValueEnum)]
 pub enum Optimization {
diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock
index 417ecb09b31..e4bfd9bd122 100644
--- a/src/tools/miri/Cargo.lock
+++ b/src/tools/miri/Cargo.lock
@@ -58,9 +58,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.82"
+version = "1.0.86"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519"
+checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
 
 [[package]]
 name = "autocfg"
@@ -85,15 +85,15 @@ dependencies = [
 
 [[package]]
 name = "bitflags"
-version = "2.5.0"
+version = "2.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
+checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
 
 [[package]]
 name = "bstr"
-version = "1.9.1"
+version = "1.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706"
+checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c"
 dependencies = [
  "memchr",
  "regex-automata",
@@ -101,10 +101,16 @@ dependencies = [
 ]
 
 [[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
 name = "camino"
-version = "1.1.6"
+version = "1.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c"
+checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239"
 dependencies = [
  "serde",
 ]
@@ -134,9 +140,9 @@ dependencies = [
 
 [[package]]
 name = "cc"
-version = "1.0.96"
+version = "1.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "065a29261d53ba54260972629f9ca6bffa69bac13cd1fed61420f7fa68b9f8bd"
+checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc"
 
 [[package]]
 name = "cfg-if"
@@ -258,18 +264,18 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-channel"
-version = "0.5.12"
+version = "0.5.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95"
+checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2"
 dependencies = [
  "crossbeam-utils",
 ]
 
 [[package]]
 name = "crossbeam-utils"
-version = "0.8.19"
+version = "0.8.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
+checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
 
 [[package]]
 name = "crypto-common"
@@ -320,9 +326,9 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
 
 [[package]]
 name = "errno"
-version = "0.3.8"
+version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
+checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
 dependencies = [
  "libc",
  "windows-sys 0.52.0",
@@ -356,9 +362,9 @@ dependencies = [
 
 [[package]]
 name = "getrandom"
-version = "0.2.14"
+version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c"
+checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
 dependencies = [
  "cfg-if",
  "libc",
@@ -401,9 +407,9 @@ dependencies = [
 
 [[package]]
 name = "instant"
-version = "0.1.12"
+version = "0.1.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
+checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
 dependencies = [
  "cfg-if",
 ]
@@ -426,9 +432,9 @@ dependencies = [
 
 [[package]]
 name = "lazy_static"
-version = "1.4.0"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
 
 [[package]]
 name = "levenshtein"
@@ -438,9 +444,9 @@ checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760"
 
 [[package]]
 name = "libc"
-version = "0.2.154"
+version = "0.2.155"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
+checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
 
 [[package]]
 name = "libffi"
@@ -463,12 +469,12 @@ dependencies = [
 
 [[package]]
 name = "libloading"
-version = "0.8.3"
+version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
+checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
 dependencies = [
  "cfg-if",
- "windows-targets 0.52.5",
+ "windows-targets 0.52.6",
 ]
 
 [[package]]
@@ -483,9 +489,9 @@ dependencies = [
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.4.13"
+version = "0.4.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
+checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
 
 [[package]]
 name = "lock_api"
@@ -499,9 +505,9 @@ dependencies = [
 
 [[package]]
 name = "log"
-version = "0.4.21"
+version = "0.4.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
+checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
 
 [[package]]
 name = "measureme"
@@ -519,9 +525,9 @@ dependencies = [
 
 [[package]]
 name = "memchr"
-version = "2.7.2"
+version = "2.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
 
 [[package]]
 name = "memmap2"
@@ -534,9 +540,9 @@ dependencies = [
 
 [[package]]
 name = "miniz_oxide"
-version = "0.7.2"
+version = "0.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
+checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
 dependencies = [
  "adler",
 ]
@@ -563,6 +569,7 @@ dependencies = [
  "smallvec",
  "tempfile",
  "ui_test",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
@@ -630,9 +637,9 @@ dependencies = [
 
 [[package]]
 name = "parking_lot"
-version = "0.12.2"
+version = "0.12.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb"
+checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
 dependencies = [
  "lock_api",
  "parking_lot_core",
@@ -648,7 +655,7 @@ dependencies = [
  "libc",
  "redox_syscall",
  "smallvec",
- "windows-targets 0.52.5",
+ "windows-targets 0.52.6",
 ]
 
 [[package]]
@@ -715,15 +722,18 @@ checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
 
 [[package]]
 name = "portable-atomic"
-version = "1.6.0"
+version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
+checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265"
 
 [[package]]
 name = "ppv-lite86"
-version = "0.2.17"
+version = "0.2.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
+checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
+dependencies = [
+ "zerocopy",
+]
 
 [[package]]
 name = "prettydiff"
@@ -737,9 +747,9 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.81"
+version = "1.0.86"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba"
+checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
 dependencies = [
  "unicode-ident",
 ]
@@ -785,9 +795,9 @@ dependencies = [
 
 [[package]]
 name = "redox_syscall"
-version = "0.5.1"
+version = "0.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e"
+checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4"
 dependencies = [
  "bitflags",
 ]
@@ -805,9 +815,9 @@ dependencies = [
 
 [[package]]
 name = "regex"
-version = "1.10.4"
+version = "1.10.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
+checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -817,9 +827,9 @@ dependencies = [
 
 [[package]]
 name = "regex-automata"
-version = "0.4.6"
+version = "0.4.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
+checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -828,15 +838,15 @@ dependencies = [
 
 [[package]]
 name = "regex-syntax"
-version = "0.8.3"
+version = "0.8.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
+checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
 
 [[package]]
 name = "rustc-demangle"
-version = "0.1.23"
+version = "0.1.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
+checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
 
 [[package]]
 name = "rustc-hash"
@@ -880,9 +890,9 @@ dependencies = [
 
 [[package]]
 name = "ryu"
-version = "1.0.17"
+version = "1.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
+checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
 
 [[package]]
 name = "scopeguard"
@@ -892,27 +902,27 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
 
 [[package]]
 name = "semver"
-version = "1.0.22"
+version = "1.0.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
+checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "serde"
-version = "1.0.200"
+version = "1.0.204"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f"
+checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.200"
+version = "1.0.204"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb"
+checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -921,11 +931,12 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.116"
+version = "1.0.122"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813"
+checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da"
 dependencies = [
  "itoa",
+ "memchr",
  "ryu",
  "serde",
 ]
@@ -953,9 +964,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
 
 [[package]]
 name = "syn"
-version = "2.0.60"
+version = "2.0.72"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3"
+checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -964,30 +975,31 @@ dependencies = [
 
 [[package]]
 name = "tempfile"
-version = "3.10.1"
+version = "3.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
+checksum = "b8fcd239983515c23a32fb82099f97d0b11b8c72f654ed659363a95c3dad7a53"
 dependencies = [
  "cfg-if",
  "fastrand",
+ "once_cell",
  "rustix",
  "windows-sys 0.52.0",
 ]
 
 [[package]]
 name = "thiserror"
-version = "1.0.59"
+version = "1.0.63"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa"
+checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.59"
+version = "1.0.63"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66"
+checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1086,9 +1098,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
 
 [[package]]
 name = "unicode-width"
-version = "0.1.12"
+version = "0.1.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6"
+checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
 
 [[package]]
 name = "valuable"
@@ -1098,9 +1110,9 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
 
 [[package]]
 name = "version_check"
-version = "0.9.4"
+version = "0.9.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
 
 [[package]]
 name = "wasi"
@@ -1145,7 +1157,7 @@ version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
 dependencies = [
- "windows-targets 0.52.5",
+ "windows-targets 0.52.6",
 ]
 
 [[package]]
@@ -1165,18 +1177,18 @@ dependencies = [
 
 [[package]]
 name = "windows-targets"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
 dependencies = [
- "windows_aarch64_gnullvm 0.52.5",
- "windows_aarch64_msvc 0.52.5",
- "windows_i686_gnu 0.52.5",
+ "windows_aarch64_gnullvm 0.52.6",
+ "windows_aarch64_msvc 0.52.6",
+ "windows_i686_gnu 0.52.6",
  "windows_i686_gnullvm",
- "windows_i686_msvc 0.52.5",
- "windows_x86_64_gnu 0.52.5",
- "windows_x86_64_gnullvm 0.52.5",
- "windows_x86_64_msvc 0.52.5",
+ "windows_i686_msvc 0.52.6",
+ "windows_x86_64_gnu 0.52.6",
+ "windows_x86_64_gnullvm 0.52.6",
+ "windows_x86_64_msvc 0.52.6",
 ]
 
 [[package]]
@@ -1187,9 +1199,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
 
 [[package]]
 name = "windows_aarch64_msvc"
@@ -1199,9 +1211,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
 
 [[package]]
 name = "windows_i686_gnu"
@@ -1211,15 +1223,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
 
 [[package]]
 name = "windows_i686_gnullvm"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
 
 [[package]]
 name = "windows_i686_msvc"
@@ -1229,9 +1241,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
 
 [[package]]
 name = "windows_x86_64_gnu"
@@ -1241,9 +1253,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
@@ -1253,9 +1265,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
 
 [[package]]
 name = "windows_x86_64_msvc"
@@ -1265,9 +1277,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 
 [[package]]
 name = "yansi-term"
@@ -1277,3 +1289,24 @@ checksum = "fe5c30ade05e61656247b2e334a031dfd0cc466fadef865bdcdea8d537951bf1"
 dependencies = [
  "winapi",
 ]
+
+[[package]]
+name = "zerocopy"
+version = "0.7.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
+dependencies = [
+ "byteorder",
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.7.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml
index 976bd080867..e12f3f9012f 100644
--- a/src/tools/miri/Cargo.toml
+++ b/src/tools/miri/Cargo.toml
@@ -9,12 +9,12 @@ default-run = "miri"
 edition = "2021"
 
 [lib]
-test = true # we have unit tests
+test = true     # we have unit tests
 doctest = false # but no doc tests
 
 [[bin]]
 name = "miri"
-test = false # we have no unit tests
+test = false    # we have no unit tests
 doctest = false # and no doc tests
 
 [dependencies]
@@ -42,6 +42,13 @@ libc = "0.2"
 libffi = "3.2.0"
 libloading = "0.8"
 
+[target.'cfg(target_family = "windows")'.dependencies]
+windows-sys = { version = "0.52", features = [
+    "Win32_Foundation",
+    "Win32_System_IO",
+    "Win32_Storage_FileSystem",
+] }
+
 [dev-dependencies]
 colored = "2"
 ui_test = "0.21.1"
diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md
index b1be596c006..a0bff386a71 100644
--- a/src/tools/miri/README.md
+++ b/src/tools/miri/README.md
@@ -212,7 +212,6 @@ degree documented below):
 - All Rust [Tier 1 targets](https://doc.rust-lang.org/rustc/platform-support.html) are supported by
   Miri. They are all checked on Miri's CI, and some (at least one per OS) are even checked on every
   Rust PR, so the shipped Miri should always work on these targets.
-- `aarch64-apple-darwin` is supported.
 - `s390x-unknown-linux-gnu` is supported as our "big-endian target of choice".
 - For every other target with OS `linux`, `macos`, or `windows`, Miri should generally work, but we
   make no promises and we don't run tests for such targets.
@@ -398,6 +397,8 @@ to Miri failing to detect cases of undefined behavior in a program.
   application instead of raising an error within the context of Miri (and halting
   execution). Note that code might not expect these operations to ever panic, so
   this flag can lead to strange (mis)behavior.
+* `-Zmiri-recursive-validation` is a *highly experimental* flag that makes validity checking
+  recurse below references.
 * `-Zmiri-retag-fields[=<all|none|scalar>]` controls when Stacked Borrows retagging recurses into
   fields. `all` means it always recurses (the default, and equivalent to `-Zmiri-retag-fields`
   without an explicit value), `none` means it never recurses, `scalar` means it only recurses for
@@ -474,6 +475,19 @@ Miri provides some `extern` functions that programs can import to access
 Miri-specific functionality. They are declared in
 [/tests/utils/miri\_extern.rs](/tests/utils/miri_extern.rs).
 
+## Entry point for no-std binaries
+
+Binaries that do not use the standard library are expected to declare a function like this so that
+Miri knows where it is supposed to start execution:
+
+```rust
+#[cfg(miri)]
+#[no_mangle]
+fn miri_start(argc: isize, argv: *const *const u8) -> isize {
+    // Call the actual start function that your project implements, based on your target's conventions.
+}
+```
+
 ## Contributing and getting help
 
 If you want to contribute to Miri, great!  Please check out our
diff --git a/src/tools/miri/cargo-miri/Cargo.lock b/src/tools/miri/cargo-miri/Cargo.lock
index 8bd8f103053..7369a3fbf09 100644
--- a/src/tools/miri/cargo-miri/Cargo.lock
+++ b/src/tools/miri/cargo-miri/Cargo.lock
@@ -4,21 +4,21 @@ version = 3
 
 [[package]]
 name = "anyhow"
-version = "1.0.82"
+version = "1.0.86"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519"
+checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
 
 [[package]]
 name = "bitflags"
-version = "2.5.0"
+version = "2.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
+checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
 
 [[package]]
 name = "camino"
-version = "1.1.6"
+version = "1.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c"
+checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239"
 dependencies = [
  "serde",
 ]
@@ -88,9 +88,9 @@ dependencies = [
 
 [[package]]
 name = "errno"
-version = "0.3.8"
+version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
+checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
 dependencies = [
  "libc",
  "windows-sys 0.52.0",
@@ -104,9 +104,9 @@ checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
 
 [[package]]
 name = "getrandom"
-version = "0.2.14"
+version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c"
+checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
 dependencies = [
  "cfg-if",
  "libc",
@@ -121,9 +121,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
 
 [[package]]
 name = "libc"
-version = "0.2.154"
+version = "0.2.155"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
+checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
 
 [[package]]
 name = "libredox"
@@ -137,9 +137,21 @@ dependencies = [
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.4.13"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
+
+[[package]]
+name = "memchr"
+version = "2.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+
+[[package]]
+name = "once_cell"
+version = "1.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
 
 [[package]]
 name = "option-ext"
@@ -149,9 +161,9 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.81"
+version = "1.0.86"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba"
+checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
 dependencies = [
  "unicode-ident",
 ]
@@ -178,9 +190,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-build-sysroot"
-version = "0.5.2"
+version = "0.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa3ca63cc537c1cb69e4c2c0afc5fda2ccd36ac84c97d5a4ae05e69b1c834afb"
+checksum = "2471f8f296262437d7e848e527b4210b44a96e53a3b4435b890227ce3e6da106"
 dependencies = [
  "anyhow",
  "rustc_version",
@@ -218,9 +230,9 @@ dependencies = [
 
 [[package]]
 name = "ryu"
-version = "1.0.17"
+version = "1.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
+checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
 
 [[package]]
 name = "same-file"
@@ -233,27 +245,27 @@ dependencies = [
 
 [[package]]
 name = "semver"
-version = "1.0.22"
+version = "1.0.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
+checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "serde"
-version = "1.0.200"
+version = "1.0.204"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f"
+checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.200"
+version = "1.0.204"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb"
+checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -262,20 +274,21 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.116"
+version = "1.0.122"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813"
+checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da"
 dependencies = [
  "itoa",
+ "memchr",
  "ryu",
  "serde",
 ]
 
 [[package]]
 name = "syn"
-version = "2.0.60"
+version = "2.0.72"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3"
+checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -284,30 +297,31 @@ dependencies = [
 
 [[package]]
 name = "tempfile"
-version = "3.10.1"
+version = "3.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
+checksum = "b8fcd239983515c23a32fb82099f97d0b11b8c72f654ed659363a95c3dad7a53"
 dependencies = [
  "cfg-if",
  "fastrand",
+ "once_cell",
  "rustix",
  "windows-sys 0.52.0",
 ]
 
 [[package]]
 name = "thiserror"
-version = "1.0.59"
+version = "1.0.63"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa"
+checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.59"
+version = "1.0.63"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66"
+checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -338,11 +352,11 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "winapi-util"
-version = "0.1.8"
+version = "0.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
+checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
 dependencies = [
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -360,7 +374,16 @@ version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
 dependencies = [
- "windows-targets 0.52.5",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets 0.52.6",
 ]
 
 [[package]]
@@ -380,18 +403,18 @@ dependencies = [
 
 [[package]]
 name = "windows-targets"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
 dependencies = [
- "windows_aarch64_gnullvm 0.52.5",
- "windows_aarch64_msvc 0.52.5",
- "windows_i686_gnu 0.52.5",
+ "windows_aarch64_gnullvm 0.52.6",
+ "windows_aarch64_msvc 0.52.6",
+ "windows_i686_gnu 0.52.6",
  "windows_i686_gnullvm",
- "windows_i686_msvc 0.52.5",
- "windows_x86_64_gnu 0.52.5",
- "windows_x86_64_gnullvm 0.52.5",
- "windows_x86_64_msvc 0.52.5",
+ "windows_i686_msvc 0.52.6",
+ "windows_x86_64_gnu 0.52.6",
+ "windows_x86_64_gnullvm 0.52.6",
+ "windows_x86_64_msvc 0.52.6",
 ]
 
 [[package]]
@@ -402,9 +425,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
 
 [[package]]
 name = "windows_aarch64_msvc"
@@ -414,9 +437,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
 
 [[package]]
 name = "windows_i686_gnu"
@@ -426,15 +449,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
 
 [[package]]
 name = "windows_i686_gnullvm"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
 
 [[package]]
 name = "windows_i686_msvc"
@@ -444,9 +467,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
 
 [[package]]
 name = "windows_x86_64_gnu"
@@ -456,9 +479,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
@@ -468,9 +491,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
 
 [[package]]
 name = "windows_x86_64_msvc"
@@ -480,6 +503,6 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
diff --git a/src/tools/miri/cargo-miri/Cargo.toml b/src/tools/miri/cargo-miri/Cargo.toml
index 6acdbc46f64..477c60db162 100644
--- a/src/tools/miri/cargo-miri/Cargo.toml
+++ b/src/tools/miri/cargo-miri/Cargo.toml
@@ -18,7 +18,7 @@ directories = "5"
 rustc_version = "0.4"
 serde_json = "1.0.40"
 cargo_metadata = "0.18.0"
-rustc-build-sysroot = "0.5.2"
+rustc-build-sysroot = "0.5.3"
 
 # Enable some feature flags that dev-dependencies need but dependencies
 # do not.  This makes `./miri install` after `./miri build` faster.
diff --git a/src/tools/miri/cargo-miri/src/setup.rs b/src/tools/miri/cargo-miri/src/setup.rs
index fe67aad465c..0cf6f1a375c 100644
--- a/src/tools/miri/cargo-miri/src/setup.rs
+++ b/src/tools/miri/cargo-miri/src/setup.rs
@@ -100,7 +100,10 @@ pub fn setup(
         // for target crates.
         let cargo_miri_path = std::env::current_exe().expect("current executable path invalid");
         if env::var_os("RUSTC_STAGE").is_some() {
-            assert!(env::var_os("RUSTC").is_some());
+            assert!(
+                env::var_os("RUSTC").is_some() && env::var_os("RUSTC_WRAPPER").is_some(),
+                "cargo-miri setup is running inside rustc bootstrap but RUSTC or RUST_WRAPPER is not set"
+            );
             command.env("RUSTC_REAL", &cargo_miri_path);
         } else {
             command.env("RUSTC", &cargo_miri_path);
diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh
index 5e75638f467..3e90ecc5c03 100755
--- a/src/tools/miri/ci/ci.sh
+++ b/src/tools/miri/ci/ci.sh
@@ -137,7 +137,7 @@ case $HOST_TARGET in
     MANY_SEEDS=16 TEST_TARGET=x86_64-pc-windows-gnu run_tests
     ;;
   aarch64-apple-darwin)
-    # Host (tier 2)
+    # Host
     GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests
     # Extra tier 1
     MANY_SEEDS=64 TEST_TARGET=i686-pc-windows-gnu run_tests
diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs
index 62a3ab2c34c..fc205040baf 100644
--- a/src/tools/miri/miri-script/src/commands.rs
+++ b/src/tools/miri/miri-script/src/commands.rs
@@ -355,7 +355,10 @@ impl Command {
         let head = cmd!(sh, "git rev-parse HEAD").read()?;
         let fetch_head = cmd!(sh, "git rev-parse FETCH_HEAD").read()?;
         if head != fetch_head {
-            bail!("Josh created a non-roundtrip push! Do NOT merge this into rustc!");
+            bail!(
+                "Josh created a non-roundtrip push! Do NOT merge this into rustc!\n\
+                Expected {head}, got {fetch_head}."
+            );
         }
         println!(
             "Confirmed that the push round-trips back to Miri properly. Please create a rustc PR:"
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index e90d3732ca5..b74f9759ebe 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-99b7134389e9766462601a2fc4013840b9d31745
+29e924841f06bb181d87494eba2783761bc1ddec
diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs
index d0f977f8143..ed955e78c3e 100644
--- a/src/tools/miri/src/alloc_addresses/mod.rs
+++ b/src/tools/miri/src/alloc_addresses/mod.rs
@@ -11,7 +11,7 @@ use rand::Rng;
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_span::Span;
-use rustc_target::abi::{Align, HasDataLayout, Size};
+use rustc_target::abi::{Align, Size};
 
 use crate::{concurrency::VClock, *};
 
@@ -105,15 +105,17 @@ impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {}
 trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
     // Returns the exposed `AllocId` that corresponds to the specified addr,
     // or `None` if the addr is out of bounds
-    fn alloc_id_from_addr(&self, addr: u64) -> Option<AllocId> {
+    fn alloc_id_from_addr(&self, addr: u64, size: i64) -> Option<AllocId> {
         let ecx = self.eval_context_ref();
         let global_state = ecx.machine.alloc_addresses.borrow();
         assert!(global_state.provenance_mode != ProvenanceMode::Strict);
 
+        // We always search the allocation to the right of this address. So if the size is structly
+        // negative, we have to search for `addr-1` instead.
+        let addr = if size >= 0 { addr } else { addr.saturating_sub(1) };
         let pos = global_state.int_to_ptr_map.binary_search_by_key(&addr, |(addr, _)| *addr);
 
         // Determine the in-bounds provenance for this pointer.
-        // (This is only called on an actual access, so in-bounds is the only possible kind of provenance.)
         let alloc_id = match pos {
             Ok(pos) => Some(global_state.int_to_ptr_map[pos].1),
             Err(0) => None,
@@ -305,20 +307,24 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         let (prov, offset) = ptr.into_parts(); // offset is relative (AllocId provenance)
         let alloc_id = prov.alloc_id();
-        let base_addr = ecx.addr_from_alloc_id(alloc_id, kind)?;
 
-        // Add offset with the right kind of pointer-overflowing arithmetic.
-        let dl = ecx.data_layout();
-        let absolute_addr = dl.overflowing_offset(base_addr, offset.bytes()).0;
-        Ok(interpret::Pointer::new(
+        // Get a pointer to the beginning of this allocation.
+        let base_addr = ecx.addr_from_alloc_id(alloc_id, kind)?;
+        let base_ptr = interpret::Pointer::new(
             Provenance::Concrete { alloc_id, tag },
-            Size::from_bytes(absolute_addr),
-        ))
+            Size::from_bytes(base_addr),
+        );
+        // Add offset with the right kind of pointer-overflowing arithmetic.
+        Ok(base_ptr.wrapping_offset(offset, ecx))
     }
 
     /// When a pointer is used for a memory access, this computes where in which allocation the
     /// access is going.
-    fn ptr_get_alloc(&self, ptr: interpret::Pointer<Provenance>) -> Option<(AllocId, Size)> {
+    fn ptr_get_alloc(
+        &self,
+        ptr: interpret::Pointer<Provenance>,
+        size: i64,
+    ) -> Option<(AllocId, Size)> {
         let ecx = self.eval_context_ref();
 
         let (tag, addr) = ptr.into_parts(); // addr is absolute (Tag provenance)
@@ -327,7 +333,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             alloc_id
         } else {
             // A wildcard pointer.
-            ecx.alloc_id_from_addr(addr.bytes())?
+            ecx.alloc_id_from_addr(addr.bytes(), size)?
         };
 
         // This cannot fail: since we already have a pointer with that provenance, adjust_alloc_root_pointer
@@ -335,12 +341,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let base_addr = *ecx.machine.alloc_addresses.borrow().base_addr.get(&alloc_id).unwrap();
 
         // Wrapping "addr - base_addr"
-        #[allow(clippy::cast_possible_wrap)] // we want to wrap here
-        let neg_base_addr = (base_addr as i64).wrapping_neg();
-        Some((
-            alloc_id,
-            Size::from_bytes(ecx.overflowing_signed_offset(addr.bytes(), neg_base_addr).0),
-        ))
+        let rel_offset = ecx.truncate_to_target_usize(addr.bytes().wrapping_sub(base_addr));
+        Some((alloc_id, Size::from_bytes(rel_offset)))
     }
 }
 
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 9f3fa075f38..e13e54c3309 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -14,11 +14,14 @@ extern crate tracing;
 extern crate rustc_data_structures;
 extern crate rustc_driver;
 extern crate rustc_hir;
+extern crate rustc_hir_analysis;
 extern crate rustc_interface;
 extern crate rustc_log;
 extern crate rustc_metadata;
 extern crate rustc_middle;
 extern crate rustc_session;
+extern crate rustc_span;
+extern crate rustc_target;
 
 use std::env::{self, VarError};
 use std::num::NonZero;
@@ -29,7 +32,9 @@ use tracing::debug;
 
 use rustc_data_structures::sync::Lrc;
 use rustc_driver::Compilation;
+use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_hir::{self as hir, Node};
+use rustc_hir_analysis::check::check_function_signature;
 use rustc_interface::interface::Config;
 use rustc_middle::{
     middle::{
@@ -37,14 +42,17 @@ use rustc_middle::{
         exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel},
     },
     query::LocalCrate,
-    ty::TyCtxt,
+    traits::{ObligationCause, ObligationCauseCode},
+    ty::{self, Ty, TyCtxt},
     util::Providers,
 };
-use rustc_session::config::{CrateType, ErrorOutputType, OptLevel};
+use rustc_session::config::{CrateType, EntryFnType, ErrorOutputType, OptLevel};
 use rustc_session::search_paths::PathKind;
 use rustc_session::{CtfeBacktrace, EarlyDiagCtxt};
+use rustc_span::def_id::DefId;
+use rustc_target::spec::abi::Abi;
 
-use miri::{BacktraceStyle, BorrowTrackerMethod, ProvenanceMode, RetagFields};
+use miri::{BacktraceStyle, BorrowTrackerMethod, ProvenanceMode, RetagFields, ValidationMode};
 
 struct MiriCompilerCalls {
     miri_config: miri::MiriConfig,
@@ -82,11 +90,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
                 tcx.dcx().fatal("miri only makes sense on bin crates");
             }
 
-            let (entry_def_id, entry_type) = if let Some(entry_def) = tcx.entry_fn(()) {
-                entry_def
-            } else {
-                tcx.dcx().fatal("miri can only run programs that have a main function");
-            };
+            let (entry_def_id, entry_type) = entry_fn(tcx);
             let mut config = self.miri_config.clone();
 
             // Add filename to `miri` arguments.
@@ -351,6 +355,56 @@ fn jemalloc_magic() {
     }
 }
 
+fn entry_fn(tcx: TyCtxt<'_>) -> (DefId, EntryFnType) {
+    if let Some(entry_def) = tcx.entry_fn(()) {
+        return entry_def;
+    }
+    // Look for a symbol in the local crate named `miri_start`, and treat that as the entry point.
+    let sym = tcx.exported_symbols(LOCAL_CRATE).iter().find_map(|(sym, _)| {
+        if sym.symbol_name_for_local_instance(tcx).name == "miri_start" { Some(sym) } else { None }
+    });
+    if let Some(ExportedSymbol::NonGeneric(id)) = sym {
+        let start_def_id = id.expect_local();
+        let start_span = tcx.def_span(start_def_id);
+
+        let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig(
+            [tcx.types.isize, Ty::new_imm_ptr(tcx, Ty::new_imm_ptr(tcx, tcx.types.u8))],
+            tcx.types.isize,
+            false,
+            hir::Safety::Safe,
+            Abi::Rust,
+        ));
+
+        let correct_func_sig = check_function_signature(
+            tcx,
+            ObligationCause::new(start_span, start_def_id, ObligationCauseCode::Misc),
+            *id,
+            expected_sig,
+        )
+        .is_ok();
+
+        if correct_func_sig {
+            (*id, EntryFnType::Start)
+        } else {
+            tcx.dcx().fatal(
+                "`miri_start` must have the following signature:\n\
+                        fn miri_start(argc: isize, argv: *const *const u8) -> isize",
+            );
+        }
+    } else {
+        tcx.dcx().fatal(
+            "Miri can only run programs that have a main function.\n\
+            Alternatively, you can export a `miri_start` function:\n\
+            \n\
+            #[cfg(miri)]\n\
+            #[no_mangle]\n\
+            fn miri_start(argc: isize, argv: *const *const u8) -> isize {\
+            \n    // Call the actual start function that your project implements, based on your target's conventions.\n\
+            }"
+        );
+    }
+}
+
 fn main() {
     #[cfg(any(target_os = "linux", target_os = "macos"))]
     jemalloc_magic();
@@ -421,7 +475,9 @@ fn main() {
         } else if arg == "--" {
             after_dashdash = true;
         } else if arg == "-Zmiri-disable-validation" {
-            miri_config.validate = false;
+            miri_config.validation = ValidationMode::No;
+        } else if arg == "-Zmiri-recursive-validation" {
+            miri_config.validation = ValidationMode::Deep;
         } else if arg == "-Zmiri-disable-stacked-borrows" {
             miri_config.borrow_tracker = None;
         } else if arg == "-Zmiri-tree-borrows" {
@@ -620,6 +676,14 @@ fn main() {
             "-Zmiri-unique-is-unique only has an effect when -Zmiri-tree-borrows is also used"
         );
     }
+    // Tree Borrows + permissive provenance does not work.
+    if miri_config.provenance_mode == ProvenanceMode::Permissive
+        && matches!(miri_config.borrow_tracker, Some(BorrowTrackerMethod::TreeBorrows))
+    {
+        show_error!(
+            "Tree Borrows does not support integer-to-pointer casts, and is hence not compatible with permissive provenance"
+        );
+    }
 
     debug!("rustc arguments: {:?}", rustc_args);
     debug!("crate arguments: {:?}", miri_config.args);
diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs
index c9e7e300593..d537a7fbc17 100644
--- a/src/tools/miri/src/borrow_tracker/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/mod.rs
@@ -232,6 +232,10 @@ impl GlobalStateInner {
     pub fn remove_unreachable_allocs(&mut self, allocs: &LiveAllocs<'_, '_>) {
         self.root_ptr_tags.retain(|id, _| allocs.is_live(*id));
     }
+
+    pub fn borrow_tracker_method(&self) -> BorrowTrackerMethod {
+        self.borrow_tracker_method
+    }
 }
 
 /// Which borrow tracking method to use
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
index 603733f9dc0..fc2b3f9c6ea 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
@@ -5,6 +5,7 @@ pub mod diagnostics;
 mod item;
 mod stack;
 
+use std::cell::RefCell;
 use std::cmp;
 use std::fmt::Write;
 use std::mem;
@@ -672,7 +673,8 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> {
             // attempt to use it for a non-zero-sized access.
             // Dangling slices are a common case here; it's valid to get their length but with raw
             // pointer tagging for example all calls to get_unchecked on them are invalid.
-            if let Ok((alloc_id, base_offset, orig_tag)) = this.ptr_try_get_alloc_id(place.ptr()) {
+            if let Ok((alloc_id, base_offset, orig_tag)) = this.ptr_try_get_alloc_id(place.ptr(), 0)
+            {
                 log_creation(this, Some((alloc_id, base_offset, orig_tag)))?;
                 // Still give it the new provenance, it got retagged after all.
                 return Ok(Some(Provenance::Concrete { alloc_id, tag: new_tag }));
@@ -684,7 +686,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> {
             }
         }
 
-        let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr())?;
+        let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr(), 0)?;
         log_creation(this, Some((alloc_id, base_offset, orig_tag)))?;
 
         trace!(
@@ -820,7 +822,19 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> {
         // See https://github.com/rust-lang/unsafe-code-guidelines/issues/276.
         let size = match size {
             Some(size) => size,
-            None => return Ok(place.clone()),
+            None => {
+                // The first time this happens, show a warning.
+                thread_local! { static WARNING_SHOWN: RefCell<bool> = const { RefCell::new(false) }; }
+                WARNING_SHOWN.with_borrow_mut(|shown| {
+                    if *shown {
+                        return;
+                    }
+                    // Not yet shown. Show it!
+                    *shown = true;
+                    this.emit_diagnostic(NonHaltingDiagnostic::ExternTypeReborrow);
+                });
+                return Ok(place.clone());
+            }
         };
 
         // Compute new borrow.
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 86074384084..44f42d5fb9c 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
@@ -141,8 +141,15 @@ impl<'tcx> NewPermission {
     ) -> Option<Self> {
         let ty_is_freeze = pointee.is_freeze(*cx.tcx, cx.param_env());
         let ty_is_unpin = pointee.is_unpin(*cx.tcx, cx.param_env());
+        let is_protected = kind == RetagKind::FnEntry;
+        // As demonstrated by `tests/fail/tree_borrows/reservedim_spurious_write.rs`,
+        // interior mutability and protectors interact poorly.
+        // To eliminate the case of Protected Reserved IM we override interior mutability
+        // in the case of a protected reference: protected references are always considered
+        // "freeze".
         let initial_state = match mutability {
-            Mutability::Mut if ty_is_unpin => Permission::new_reserved(ty_is_freeze),
+            Mutability::Mut if ty_is_unpin =>
+                Permission::new_reserved(ty_is_freeze || is_protected),
             Mutability::Not if ty_is_freeze => Permission::new_frozen(),
             // Raw pointers never enter this function so they are not handled.
             // However raw pointers are not the only pointers that take the parent
@@ -151,7 +158,7 @@ impl<'tcx> NewPermission {
             _ => return None,
         };
 
-        let protector = (kind == RetagKind::FnEntry).then_some(ProtectorKind::StrongProtector);
+        let protector = is_protected.then_some(ProtectorKind::StrongProtector);
         Some(Self { zero_size: false, initial_state, protector })
     }
 
@@ -216,7 +223,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         };
 
         trace!("Reborrow of size {:?}", ptr_size);
-        let (alloc_id, base_offset, parent_prov) = match this.ptr_try_get_alloc_id(place.ptr()) {
+        let (alloc_id, base_offset, parent_prov) = match this.ptr_try_get_alloc_id(place.ptr(), 0) {
             Ok(data) => {
                 // Unlike SB, we *do* a proper retag for size 0 if can identify the allocation.
                 // After all, the pointer may be lazily initialized outside this initial range.
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 7aa9c3e862b..8e23257b6c0 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
@@ -22,6 +22,11 @@ enum PermissionPriv {
     /// - foreign-read then child-write is UB due to `conflicted`,
     /// - child-write then foreign-read is UB since child-write will activate and then
     ///   foreign-read disables a protected `Active`, which is UB.
+    ///
+    /// Note: since the discovery of `tests/fail/tree_borrows/reservedim_spurious_write.rs`,
+    /// `ty_is_freeze` does not strictly mean that the type has no interior mutability,
+    /// it could be an interior mutable type that lost its interior mutability privileges
+    /// when retagged with a protector.
     Reserved { ty_is_freeze: bool, conflicted: bool },
     /// represents: a unique pointer;
     /// allows: child reads, child writes;
@@ -141,6 +146,12 @@ mod transition {
     /// non-protected interior mutable `Reserved` which stay the same.
     fn foreign_write(state: PermissionPriv, protected: bool) -> Option<PermissionPriv> {
         Some(match state {
+            // FIXME: since the fix related to reservedim_spurious_write, it is now possible
+            // to express these transitions of the state machine without an explicit dependency
+            // on `protected`: because `ty_is_freeze: false` implies `!protected` then
+            // the line handling `Reserved { .. } if protected` could be deleted.
+            // This will however require optimizations to the exhaustive tests because
+            // fewer initial conditions are valid.
             Reserved { .. } if protected => Disabled,
             res @ Reserved { ty_is_freeze: false, .. } => res,
             _ => Disabled,
diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs
index 2baa09bec16..9df0d95f1f2 100644
--- a/src/tools/miri/src/concurrency/data_race.rs
+++ b/src/tools/miri/src/concurrency/data_race.rs
@@ -1180,7 +1180,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
         // We avoid `get_ptr_alloc` since we do *not* want to run the access hooks -- the actual
         // access will happen later.
         let (alloc_id, _offset, _prov) = this
-            .ptr_try_get_alloc_id(place.ptr())
+            .ptr_try_get_alloc_id(place.ptr(), 0)
             .expect("there are no zero-sized atomic accesses");
         if this.get_alloc_mutability(alloc_id)? == Mutability::Not {
             // See if this is fine.
@@ -1307,7 +1307,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
         if let Some(data_race) = &this.machine.data_race {
             if data_race.race_detecting() {
                 let size = place.layout.size;
-                let (alloc_id, base_offset, _prov) = this.ptr_get_alloc_id(place.ptr())?;
+                let (alloc_id, base_offset, _prov) = this.ptr_get_alloc_id(place.ptr(), 0)?;
                 // Load and log the atomic operation.
                 // Note that atomic loads are possible even from read-only allocations, so `get_alloc_extra_mut` is not an option.
                 let alloc_meta = this.get_alloc_extra(alloc_id)?.data_race.as_ref().unwrap();
diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs
index a53dd7eac1e..f72591f0c4b 100644
--- a/src/tools/miri/src/concurrency/thread.rs
+++ b/src/tools/miri/src/concurrency/thread.rs
@@ -256,7 +256,7 @@ pub struct Thread<'tcx> {
     /// which then forwards it to 'Resume'. However this argument is implicit in MIR,
     /// so we have to store it out-of-band. When there are multiple active unwinds,
     /// the innermost one is always caught first, so we can store them as a stack.
-    pub(crate) panic_payloads: Vec<Scalar>,
+    pub(crate) panic_payloads: Vec<ImmTy<'tcx>>,
 
     /// Last OS error location in memory. It is a 32-bit integer.
     pub(crate) last_error: Option<MPlaceTy<'tcx>>,
@@ -377,10 +377,6 @@ impl VisitProvenance for Frame<'_, Provenance, FrameExtra<'_>> {
             return_place,
             locals,
             extra,
-            body: _,
-            instance: _,
-            return_to_block: _,
-            loc: _,
             // There are some private fields we cannot access; they contain no tags.
             ..
         } = self;
@@ -952,7 +948,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         this.call_function(
             instance,
             start_abi,
-            &[*func_arg],
+            &[func_arg],
             Some(&ret_place),
             StackPopCleanup::Root { cleanup: true },
         )?;
diff --git a/src/tools/miri/src/concurrency/weak_memory.rs b/src/tools/miri/src/concurrency/weak_memory.rs
index e92eaa8f91f..6f4171584a8 100644
--- a/src/tools/miri/src/concurrency/weak_memory.rs
+++ b/src/tools/miri/src/concurrency/weak_memory.rs
@@ -468,7 +468,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         init: Scalar,
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
-        let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr())?;
+        let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr(), 0)?;
         if let (
             crate::AllocExtra { weak_memory: Some(alloc_buffers), .. },
             crate::MiriMachine { data_race: Some(global), threads, .. },
@@ -495,7 +495,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     ) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_ref();
         if let Some(global) = &this.machine.data_race {
-            let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr())?;
+            let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr(), 0)?;
             if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() {
                 if atomic == AtomicReadOrd::SeqCst {
                     global.sc_read(&this.machine.threads);
@@ -535,7 +535,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         init: Scalar,
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
-        let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(dest.ptr())?;
+        let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(dest.ptr(), 0)?;
         if let (
             crate::AllocExtra { weak_memory: Some(alloc_buffers), .. },
             crate::MiriMachine { data_race: Some(global), threads, .. },
@@ -585,7 +585,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 global.sc_read(&this.machine.threads);
             }
             let size = place.layout.size;
-            let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr())?;
+            let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr(), 0)?;
             if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() {
                 let buffer = alloc_buffers
                     .get_or_create_store_buffer(alloc_range(base_offset, size), init)?;
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index 647d7d44bb1..1bed55743d4 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -130,6 +130,7 @@ pub enum NonHaltingDiagnostic {
     WeakMemoryOutdatedLoad {
         ptr: Pointer,
     },
+    ExternTypeReborrow,
 }
 
 /// Level of Miri specific diagnostics
@@ -139,6 +140,15 @@ pub enum DiagLevel {
     Note,
 }
 
+/// Generate a note/help text without a span.
+macro_rules! note {
+    ($($tt:tt)*) => { (None, format!($($tt)*)) };
+}
+/// Generate a note/help text with a span.
+macro_rules! note_span {
+    ($span:expr, $($tt:tt)*) => { (Some($span), format!($($tt)*)) };
+}
+
 /// Attempts to prune a stacktrace to omit the Rust runtime, and returns a bool indicating if any
 /// frames were pruned. If the stacktrace does not have any local frames, we conclude that it must
 /// be pointing to a problem in the Rust runtime itself, and do not prune it at all.
@@ -227,38 +237,38 @@ pub fn report_error<'tcx>(
         let helps = match info {
             UnsupportedInIsolation(_) =>
                 vec![
-                    (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")),
+                    note!("set `MIRIFLAGS=-Zmiri-disable-isolation` to disable isolation;"),
+                    note!("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![
-                    (None, format!("if this is a basic API commonly used on this target, please report an issue with Miri")),
-                    (None, format!("however, note that Miri does not aim to support every FFI function out there; for instance, we will not support APIs for things such as GUIs, scripting languages, or databases")),
+                    note!("if this is a basic API commonly used on this target, please report an issue with Miri"),
+                    note!("however, note that Miri does not aim to support every FFI function out there; for instance, we will not support APIs for things such as GUIs, scripting languages, or databases"),
                 ]
             }
             StackedBorrowsUb { help, history, .. } => {
                 msg.extend(help.clone());
                 let mut helps = vec![
-                    (None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental")),
-                    (None, format!("see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information")),
+                    note!("this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental"),
+                    note!("see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information"),
                 ];
                 if let Some(TagHistory {created, invalidated, protected}) = history.clone() {
                     helps.push((Some(created.1), created.0));
                     if let Some((msg, span)) = invalidated {
-                        helps.push((Some(span), msg));
+                        helps.push(note_span!(span, "{msg}"));
                     }
                     if let Some((protector_msg, protector_span)) = protected {
-                        helps.push((Some(protector_span), protector_msg));
+                        helps.push(note_span!(protector_span, "{protector_msg}"));
                     }
                 }
                 helps
             },
             TreeBorrowsUb { title: _, details, history } => {
                 let mut helps = vec![
-                    (None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental"))
+                    note!("this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental")
                 ];
                 for m in details {
-                    helps.push((None, m.clone()));
+                    helps.push(note!("{m}"));
                 }
                 for event in history.events.clone() {
                     helps.push(event);
@@ -267,26 +277,26 @@ pub fn report_error<'tcx>(
             }
             MultipleSymbolDefinitions { first, first_crate, second, second_crate, .. } =>
                 vec![
-                    (Some(*first), format!("it's first defined here, in crate `{first_crate}`")),
-                    (Some(*second), format!("then it's defined here again, in crate `{second_crate}`")),
+                    note_span!(*first, "it's first defined here, in crate `{first_crate}`"),
+                    note_span!(*second, "then it's defined here again, in crate `{second_crate}`"),
                 ],
             SymbolShimClashing { link_name, span } =>
-                vec![(Some(*span), format!("the `{link_name}` symbol is defined here"))],
+                vec![note_span!(*span, "the `{link_name}` symbol is defined here")],
             Int2PtrWithStrictProvenance =>
-                vec![(None, format!("use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead"))],
+                vec![note!("use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead")],
             DataRace { op1, extra, retag_explain, .. } => {
-                let mut helps = vec![(Some(op1.span), format!("and (1) occurred earlier here"))];
+                let mut helps = vec![note_span!(op1.span, "and (1) occurred earlier here")];
                 if let Some(extra) = extra {
-                    helps.push((None, format!("{extra}")));
-                    helps.push((None, format!("see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model")));
+                    helps.push(note!("{extra}"));
+                    helps.push(note!("see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model"));
                 }
                 if *retag_explain {
-                    helps.push((None, "retags occur on all (re)borrows and as well as when references are copied or moved".to_owned()));
-                    helps.push((None, "retags permit optimizations that insert speculative reads or writes".to_owned()));
-                    helps.push((None, "therefore from the perspective of data races, a retag has the same implications as a read or write".to_owned()));
+                    helps.push(note!("retags occur on all (re)borrows and as well as when references are copied or moved"));
+                    helps.push(note!("retags permit optimizations that insert speculative reads or writes"));
+                    helps.push(note!("therefore from the perspective of data races, a retag has the same implications as a read or write"));
                 }
-                helps.push((None, format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior")));
-                helps.push((None, format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information")));
+                helps.push(note!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior"));
+                helps.push(note!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information"));
                 helps
             }
                 ,
@@ -331,32 +341,32 @@ pub fn report_error<'tcx>(
         let helps = match e.kind() {
             Unsupported(_) =>
                 vec![
-                    (None, format!("this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support")),
+                    note!("this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support"),
                 ],
             UndefinedBehavior(AlignmentCheckFailed { .. })
                 if ecx.machine.check_alignment == AlignmentCheck::Symbolic
             =>
                 vec![
-                    (None, format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior")),
-                    (None, format!("but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives")),
+                    note!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior"),
+                    note!("but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives"),
                 ],
             UndefinedBehavior(info) => {
                 let mut helps = vec![
-                    (None, format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior")),
-                    (None, format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information")),
+                    note!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior"),
+                    note!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information"),
                 ];
                 match info {
                     PointerUseAfterFree(alloc_id, _) | PointerOutOfBounds { alloc_id, .. } => {
                         if let Some(span) = ecx.machine.allocated_span(*alloc_id) {
-                            helps.push((Some(span), format!("{:?} was allocated here:", alloc_id)));
+                            helps.push(note_span!(span, "{:?} was allocated here:", alloc_id));
                         }
                         if let Some(span) = ecx.machine.deallocated_span(*alloc_id) {
-                            helps.push((Some(span), format!("{:?} was deallocated here:", alloc_id)));
+                            helps.push(note_span!(span, "{:?} was deallocated here:", alloc_id));
                         }
                     }
                     AbiMismatchArgument { .. } | AbiMismatchReturn { .. } => {
-                        helps.push((None, format!("this means these two types are not *guaranteed* to be ABI-compatible across all targets")));
-                        helps.push((None, format!("if you think this code should be accepted anyway, please report an issue with Miri")));
+                        helps.push(note!("this means these two types are not *guaranteed* to be ABI-compatible across all targets"));
+                        helps.push(note!("if you think this code should be accepted anyway, please report an issue with Miri"));
                     }
                     _ => {},
                 }
@@ -593,6 +603,8 @@ impl<'tcx> MiriMachine<'tcx> {
             RejectedIsolatedOp(_) =>
                 ("operation rejected by isolation".to_string(), DiagLevel::Warning),
             Int2Ptr { .. } => ("integer-to-pointer cast".to_string(), DiagLevel::Warning),
+            ExternTypeReborrow =>
+                ("reborrow of reference to `extern type`".to_string(), DiagLevel::Warning),
             CreatedPointerTag(..)
             | PoppedPointerTag(..)
             | CreatedCallId(..)
@@ -630,51 +642,56 @@ impl<'tcx> MiriMachine<'tcx> {
             Int2Ptr { .. } => format!("integer-to-pointer cast"),
             WeakMemoryOutdatedLoad { ptr } =>
                 format!("weak memory emulation: outdated value returned from load at {ptr}"),
+            ExternTypeReborrow =>
+                format!("reborrow of a reference to `extern type` is not properly supported"),
         };
 
         let notes = match &e {
             ProgressReport { block_count } => {
-                // It is important that each progress report is slightly different, since
-                // identical diagnostics are being deduplicated.
-                vec![(None, format!("so far, {block_count} basic blocks have been executed"))]
+                vec![note!("so far, {block_count} basic blocks have been executed")]
             }
             _ => vec![],
         };
 
         let helps = match &e {
-            Int2Ptr { details: true } =>
-                vec![
-                    (
-                        None,
-                        format!(
-                            "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."
-                        ),
+            Int2Ptr { details: true } => {
+                let mut v = vec![
+                    note!(
+                        "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"
+                    ),
+                    note!(
+                        "see https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation"
                     ),
-                    (
-                        None,
-                        format!(
-                            "See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation."
-                        ),
+                    note!(
+                        "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"
                     ),
-                    (
-                        None,
-                        format!(
-                            "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."
-                        ),
+                    note!(
+                        "you can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics"
                     ),
-                    (
-                        None,
-                        format!(
-                            "You can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics."
-                        ),
+                ];
+                if self.borrow_tracker.as_ref().is_some_and(|b| {
+                    matches!(b.borrow().borrow_tracker_method(), BorrowTrackerMethod::TreeBorrows)
+                }) {
+                    v.push(
+                        note!("Tree Borrows does not support integer-to-pointer casts, so the program is likely to go wrong when this pointer gets used")
+                    );
+                } else {
+                    v.push(
+                        note!("alternatively, `MIRIFLAGS=-Zmiri-permissive-provenance` disables this warning")
+                    );
+                }
+                v
+            }
+            ExternTypeReborrow => {
+                vec![
+                    note!(
+                        "`extern type` are not compatible with the Stacked Borrows aliasing model implemented by Miri; Miri may miss bugs in this code"
                     ),
-                    (
-                        None,
-                        format!(
-                            "Alternatively, `MIRIFLAGS=-Zmiri-permissive-provenance` disables this warning."
-                        ),
+                    note!(
+                        "try running with `MIRIFLAGS=-Zmiri-tree-borrows` to use the more permissive but also even more experimental Tree Borrows aliasing checks instead"
                     ),
-                ],
+                ]
+            }
             _ => vec![],
         };
 
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index 2184a4426c8..d781188cd0c 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -68,7 +68,7 @@ pub enum IsolatedOp {
     Allow,
 }
 
-#[derive(Copy, Clone, PartialEq, Eq)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
 pub enum BacktraceStyle {
     /// Prints a terser backtrace which ideally only contains relevant information.
     Short,
@@ -78,6 +78,16 @@ pub enum BacktraceStyle {
     Off,
 }
 
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum ValidationMode {
+    /// Do not perform any kind of validation.
+    No,
+    /// Validate the interior of the value, but not things behind references.
+    Shallow,
+    /// Fully recursively validate references.
+    Deep,
+}
+
 /// Configuration needed to spawn a Miri instance.
 #[derive(Clone)]
 pub struct MiriConfig {
@@ -85,7 +95,7 @@ pub struct MiriConfig {
     /// (This is still subject to isolation as well as `forwarded_env_vars`.)
     pub env: Vec<(OsString, OsString)>,
     /// Determine if validity checking is enabled.
-    pub validate: bool,
+    pub validation: ValidationMode,
     /// Determines if Stacked Borrows or Tree Borrows is enabled.
     pub borrow_tracker: Option<BorrowTrackerMethod>,
     /// Whether `core::ptr::Unique` receives special treatment.
@@ -162,7 +172,7 @@ impl Default for MiriConfig {
     fn default() -> MiriConfig {
         MiriConfig {
             env: vec![],
-            validate: true,
+            validation: ValidationMode::Shallow,
             borrow_tracker: Some(BorrowTrackerMethod::StackedBorrows),
             unique_is_unique: false,
             check_alignment: AlignmentCheck::Int,
@@ -297,7 +307,8 @@ pub fn create_ecx<'tcx>(
     // First argument is constructed later, because it's skipped if the entry function uses #[start].
 
     // Second argument (argc): length of `config.args`.
-    let argc = Scalar::from_target_usize(u64::try_from(config.args.len()).unwrap(), &ecx);
+    let argc =
+        ImmTy::from_int(i64::try_from(config.args.len()).unwrap(), ecx.machine.layouts.isize);
     // Third argument (`argv`): created from `config.args`.
     let argv = {
         // Put each argument in memory, collect pointers.
@@ -324,13 +335,11 @@ pub fn create_ecx<'tcx>(
             ecx.write_immediate(arg, &place)?;
         }
         ecx.mark_immutable(&argvs_place);
-        // A pointer to that place is the 3rd argument for main.
-        let argv = argvs_place.to_ref(&ecx);
         // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`.
         {
             let argc_place =
                 ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into())?;
-            ecx.write_scalar(argc, &argc_place)?;
+            ecx.write_immediate(*argc, &argc_place)?;
             ecx.mark_immutable(&argc_place);
             ecx.machine.argc = Some(argc_place.ptr());
 
@@ -338,7 +347,7 @@ pub fn create_ecx<'tcx>(
                 ecx.layout_of(Ty::new_imm_ptr(tcx, tcx.types.unit))?,
                 MiriMemoryKind::Machine.into(),
             )?;
-            ecx.write_immediate(argv, &argv_place)?;
+            ecx.write_pointer(argvs_place.ptr(), &argv_place)?;
             ecx.mark_immutable(&argv_place);
             ecx.machine.argv = Some(argv_place.ptr());
         }
@@ -359,7 +368,7 @@ pub fn create_ecx<'tcx>(
             }
             ecx.mark_immutable(&cmd_place);
         }
-        argv
+        ecx.mplace_to_ref(&argvs_place)?
     };
 
     // Return place (in static memory so that it does not count as leak).
@@ -395,10 +404,14 @@ pub fn create_ecx<'tcx>(
                 start_instance,
                 Abi::Rust,
                 &[
-                    Scalar::from_pointer(main_ptr, &ecx).into(),
-                    argc.into(),
+                    ImmTy::from_scalar(
+                        Scalar::from_pointer(main_ptr, &ecx),
+                        // FIXME use a proper fn ptr type
+                        ecx.machine.layouts.const_raw_ptr,
+                    ),
+                    argc,
                     argv,
-                    Scalar::from_u8(sigpipe).into(),
+                    ImmTy::from_uint(sigpipe, ecx.machine.layouts.u8),
                 ],
                 Some(&ret_place),
                 StackPopCleanup::Root { cleanup: true },
@@ -408,7 +421,7 @@ pub fn create_ecx<'tcx>(
             ecx.call_function(
                 entry_instance,
                 Abi::Rust,
-                &[argc.into(), argv],
+                &[argc, argv],
                 Some(&ret_place),
                 StackPopCleanup::Root { cleanup: true },
             )?;
@@ -450,6 +463,7 @@ pub fn eval_entry<'tcx>(
     let res = match res {
         Err(res) => res,
         // `Ok` can never happen
+        #[cfg(bootstrap)]
         Ok(never) => match never {},
     };
 
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index ba094c988e5..1bdf9f06dcd 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -12,13 +12,14 @@ use rustc_apfloat::Float;
 use rustc_hir::{
     def::{DefKind, Namespace},
     def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE},
+    Safety,
 };
 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;
-use rustc_middle::ty::layout::MaybeResult;
+use rustc_middle::ty::layout::{FnAbiOf, MaybeResult};
 use rustc_middle::ty::{
     self,
     layout::{LayoutOf, TyAndLayout},
@@ -492,48 +493,38 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         &mut self,
         f: ty::Instance<'tcx>,
         caller_abi: Abi,
-        args: &[Immediate<Provenance>],
+        args: &[ImmTy<'tcx>],
         dest: Option<&MPlaceTy<'tcx>>,
         stack_pop: StackPopCleanup,
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
-        let param_env = ty::ParamEnv::reveal_all(); // in Miri this is always the param_env we use... and this.param_env is private.
-        let callee_abi = f.ty(*this.tcx, param_env).fn_sig(*this.tcx).abi();
-        if callee_abi != caller_abi {
-            throw_ub_format!(
-                "calling a function with ABI {} using caller ABI {}",
-                callee_abi.name(),
-                caller_abi.name()
-            )
-        }
 
-        // Push frame.
+        // Get MIR.
         let mir = this.load_mir(f.def, None)?;
         let dest = match dest {
             Some(dest) => dest.clone(),
             None => MPlaceTy::fake_alloc_zst(this.layout_of(mir.return_ty())?),
         };
-        this.push_stack_frame(f, mir, &dest, stack_pop)?;
-
-        // Initialize arguments.
-        let mut callee_args = this.frame().body.args_iter();
-        for arg in args {
-            let local = callee_args
-                .next()
-                .ok_or_else(|| err_ub_format!("callee has fewer arguments than expected"))?;
-            // Make the local live, and insert the initial value.
-            this.storage_live(local)?;
-            let callee_arg = this.local_to_place(local)?;
-            this.write_immediate(*arg, &callee_arg)?;
-        }
-        if callee_args.next().is_some() {
-            throw_ub_format!("callee has more arguments than expected");
-        }
-
-        // Initialize remaining locals.
-        this.storage_live_for_always_live_locals()?;
 
-        Ok(())
+        // Construct a function pointer type representing the caller perspective.
+        let sig = this.tcx.mk_fn_sig(
+            args.iter().map(|a| a.layout.ty),
+            dest.layout.ty,
+            /*c_variadic*/ false,
+            Safety::Safe,
+            caller_abi,
+        );
+        let caller_fn_abi = this.fn_abi_of_fn_ptr(ty::Binder::dummy(sig), ty::List::empty())?;
+
+        this.init_stack_frame(
+            f,
+            mir,
+            caller_fn_abi,
+            &args.iter().map(|a| FnArg::Copy(a.clone().into())).collect::<Vec<_>>(),
+            /*with_caller_location*/ false,
+            &dest,
+            stack_pop,
+        )
     }
 
     /// Visits the memory covered by `place`, sensitive to freezing: the 2nd parameter
@@ -606,7 +597,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         }
         // The part between the end_ptr and the end of the place is also frozen.
         // So pretend there is a 0-sized `UnsafeCell` at the end.
-        unsafe_cell_action(&place.ptr().offset(size, this)?, Size::ZERO)?;
+        unsafe_cell_action(&place.ptr().wrapping_offset(size, this), Size::ZERO)?;
         // Done!
         return Ok(());
 
@@ -975,7 +966,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         loop {
             // FIXME: We are re-getting the allocation each time around the loop.
             // Would be nice if we could somehow "extend" an existing AllocRange.
-            let alloc = this.get_ptr_alloc(ptr.offset(len, this)?, size1)?.unwrap(); // not a ZST, so we will get a result
+            let alloc = this.get_ptr_alloc(ptr.wrapping_offset(len, this), size1)?.unwrap(); // not a ZST, so we will get a result
             let byte = alloc.read_integer(alloc_range(Size::ZERO, size1))?.to_u8()?;
             if byte == 0 {
                 break;
@@ -1039,7 +1030,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 break;
             } else {
                 wchars.push(wchar_int.try_into().unwrap());
-                ptr = ptr.offset(size, this)?;
+                ptr = ptr.wrapping_offset(size, this);
             }
         }
 
@@ -1114,12 +1105,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Make an attempt to get at the instance of the function this is inlined from.
         let instance: Option<_> = try {
             let scope = frame.current_source_info()?.scope;
-            let inlined_parent = frame.body.source_scopes[scope].inlined_parent_scope?;
-            let source = &frame.body.source_scopes[inlined_parent];
+            let inlined_parent = frame.body().source_scopes[scope].inlined_parent_scope?;
+            let source = &frame.body().source_scopes[inlined_parent];
             source.inlined.expect("inlined_parent_scope points to scope without inline info").0
         };
         // Fall back to the instance of the function itself.
-        let instance = instance.unwrap_or(frame.instance);
+        let instance = instance.unwrap_or(frame.instance());
         // Now check the crate it is in. We could try to be clever here and e.g. check if this is
         // the same crate as `start_fn`, but that would not work for running std tests in Miri, so
         // we'd need some more hacks anyway. So we just check the name of the crate. If someone
@@ -1359,9 +1350,9 @@ impl<'tcx> MiriMachine<'tcx> {
 
     /// This is the source of truth for the `is_user_relevant` flag in our `FrameExtra`.
     pub fn is_user_relevant(&self, frame: &Frame<'tcx, Provenance>) -> bool {
-        let def_id = frame.instance.def_id();
+        let def_id = frame.instance().def_id();
         (def_id.is_local() || self.local_crates.contains(&def_id.krate))
-            && !frame.instance.def.requires_caller_location(self.tcx)
+            && !frame.instance().def.requires_caller_location(self.tcx)
     }
 }
 
diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs
index 9cd776c9371..18b22827bdb 100644
--- a/src/tools/miri/src/intrinsics/mod.rs
+++ b/src/tools/miri/src/intrinsics/mod.rs
@@ -33,7 +33,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
 
         // See if the core engine can handle this intrinsic.
-        if this.emulate_intrinsic(instance, args, dest, ret)? {
+        if this.eval_intrinsic(instance, args, dest, ret)? {
             return Ok(None);
         }
         let intrinsic_name = this.tcx.item_name(instance.def_id());
@@ -153,7 +153,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Would not be considered UB, or the other way around (`is_val_statically_known(0)`).
             "is_val_statically_known" => {
                 let [arg] = check_arg_count(args)?;
-                this.validate_operand(arg)?;
+                this.validate_operand(arg, /*recursive*/ false)?;
                 let branch: bool = this.machine.rng.get_mut().gen();
                 this.write_scalar(Scalar::from_bool(branch), dest)?;
             }
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 7fb68d782f1..966d38508f6 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -10,7 +10,6 @@
 #![feature(yeet_expr)]
 #![feature(nonzero_ops)]
 #![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(lint_reasons))]
 #![feature(trait_upcasting)]
 #![feature(strict_overflow_ops)]
 #![feature(is_none_or)]
@@ -57,6 +56,7 @@ extern crate either;
 extern crate tracing;
 
 // The rustc crates we need
+extern crate rustc_attr;
 extern crate rustc_apfloat;
 extern crate rustc_ast;
 extern crate rustc_const_eval;
@@ -143,6 +143,7 @@ pub use crate::diagnostics::{
 };
 pub use crate::eval::{
     create_ecx, eval_entry, AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, RejectOpWith,
+    ValidationMode,
 };
 pub use crate::helpers::{AccessKind, EvalContextExt as _};
 pub use crate::machine::{
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index adb84593561..754f8cf1381 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -11,6 +11,7 @@ use rand::rngs::StdRng;
 use rand::Rng;
 use rand::SeedableRng;
 
+use rustc_attr::InlineAttr;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 #[allow(unused)]
 use rustc_data_structures::static_assert_size;
@@ -23,6 +24,7 @@ use rustc_middle::{
         Instance, Ty, TyCtxt,
     },
 };
+use rustc_session::config::InliningThreshold;
 use rustc_span::def_id::{CrateNum, DefId};
 use rustc_span::{Span, SpanData, Symbol};
 use rustc_target::abi::{Align, Size};
@@ -47,10 +49,10 @@ pub const SIGRTMIN: i32 = 34;
 /// `SIGRTMAX` - `SIGRTMIN` >= 8 (which is the value of `_POSIX_RTSIG_MAX`)
 pub const SIGRTMAX: i32 = 42;
 
-/// Each const has multiple addresses, but only this many. Since const allocations are never
-/// deallocated, choosing a new [`AllocId`] and thus base address for each evaluation would
-/// produce unbounded memory usage.
-const ADDRS_PER_CONST: usize = 16;
+/// Each anonymous global (constant, vtable, function pointer, ...) has multiple addresses, but only
+/// this many. Since const allocations are never deallocated, choosing a new [`AllocId`] and thus
+/// base address for each evaluation would produce unbounded memory usage.
+const ADDRS_PER_ANON_GLOBAL: usize = 32;
 
 /// Extra data stored with each stack frame
 pub struct FrameExtra<'tcx> {
@@ -187,7 +189,11 @@ impl fmt::Display for MiriMemoryKind {
 pub type MemoryKind = interpret::MemoryKind<MiriMemoryKind>;
 
 /// Pointer provenance.
-#[derive(Clone, Copy)]
+// This needs to be `Eq`+`Hash` because the `Machine` trait needs that because validity checking
+// *might* be recursive and then it has to track which places have already been visited.
+// These implementations are a bit questionable, and it means we may check the same place multiple
+// times with different provenance, but that is in general not wrong.
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
 pub enum Provenance {
     /// For pointers with concrete provenance. we exactly know which allocation they are attached to
     /// and what their borrow tag is.
@@ -215,24 +221,6 @@ pub enum Provenance {
     Wildcard,
 }
 
-// This needs to be `Eq`+`Hash` because the `Machine` trait needs that because validity checking
-// *might* be recursive and then it has to track which places have already been visited.
-// However, comparing provenance is meaningless, since `Wildcard` might be any provenance -- and of
-// course we don't actually do recursive checking.
-// We could change `RefTracking` to strip provenance for its `seen` set but that type is generic so that is quite annoying.
-// Instead owe add the required instances but make them panic.
-impl PartialEq for Provenance {
-    fn eq(&self, _other: &Self) -> bool {
-        panic!("Provenance must not be compared")
-    }
-}
-impl Eq for Provenance {}
-impl std::hash::Hash for Provenance {
-    fn hash<H: std::hash::Hasher>(&self, _state: &mut H) {
-        panic!("Provenance must not be hashed")
-    }
-}
-
 /// The "extra" information a pointer has over a regular AllocId.
 #[derive(Copy, Clone, PartialEq)]
 pub enum ProvenanceExtra {
@@ -460,7 +448,7 @@ pub struct MiriMachine<'tcx> {
     pub(crate) isolated_op: IsolatedOp,
 
     /// Whether to enforce the validity invariant.
-    pub(crate) validate: bool,
+    pub(crate) validation: ValidationMode,
 
     /// The table of file descriptors.
     pub(crate) fds: shims::FdTable,
@@ -659,8 +647,8 @@ impl<'tcx> MiriMachine<'tcx> {
             cmd_line: None,
             tls: TlsData::default(),
             isolated_op: config.isolated_op,
-            validate: config.validate,
-            fds: shims::FdTable::new(config.mute_stdout_stderr),
+            validation: config.validation,
+            fds: shims::FdTable::init(config.mute_stdout_stderr),
             dirs: Default::default(),
             layouts,
             threads,
@@ -801,7 +789,7 @@ impl VisitProvenance for MiriMachine<'_> {
             fds,
             tcx: _,
             isolated_op: _,
-            validate: _,
+            validation: _,
             clock: _,
             layouts: _,
             static_roots: _,
@@ -943,7 +931,14 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
 
     #[inline(always)]
     fn enforce_validity(ecx: &MiriInterpCx<'tcx>, _layout: TyAndLayout<'tcx>) -> bool {
-        ecx.machine.validate
+        ecx.machine.validation != ValidationMode::No
+    }
+    #[inline(always)]
+    fn enforce_validity_recursively(
+        ecx: &InterpCx<'tcx, Self>,
+        _layout: TyAndLayout<'tcx>,
+    ) -> bool {
+        ecx.machine.validation == ValidationMode::Deep
     }
 
     #[inline(always)]
@@ -1198,19 +1193,23 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         }
     }
 
-    /// Convert a pointer with provenance into an allocation-offset pair,
-    /// or a `None` with an absolute address if that conversion is not possible.
+    /// Convert a pointer with provenance into an allocation-offset pair and extra provenance info.
+    /// `size` says how many bytes of memory are expected at that pointer. The *sign* of `size` can
+    /// be used to disambiguate situations where a wildcard pointer sits right in between two
+    /// allocations.
     ///
-    /// This is called when a pointer is about to be used for memory access,
-    /// an in-bounds check, or anything else that requires knowing which allocation it points to.
+    /// If `ptr.provenance.get_alloc_id()` is `Some(p)`, the returned `AllocId` must be `p`.
     /// The resulting `AllocId` will just be used for that one step and the forgotten again
     /// (i.e., we'll never turn the data returned here back into a `Pointer` that might be
     /// stored in machine state).
+    ///
+    /// When this fails, that means the pointer does not point to a live allocation.
     fn ptr_get_alloc(
         ecx: &MiriInterpCx<'tcx>,
         ptr: StrictPointer,
+        size: i64,
     ) -> Option<(AllocId, Size, Self::ProvenanceExtra)> {
-        let rel = ecx.ptr_get_alloc(ptr);
+        let rel = ecx.ptr_get_alloc(ptr, size);
 
         rel.map(|(alloc_id, size)| {
             let tag = match ptr.provenance {
@@ -1355,7 +1354,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
     ) -> InterpResult<'tcx, Frame<'tcx, Provenance, FrameExtra<'tcx>>> {
         // Start recording our event before doing anything else
         let timing = if let Some(profiler) = ecx.machine.profiler.as_ref() {
-            let fn_name = frame.instance.to_string();
+            let fn_name = frame.instance().to_string();
             let entry = ecx.machine.string_cache.entry(fn_name.clone());
             let name = entry.or_insert_with(|| profiler.alloc_string(&*fn_name));
 
@@ -1375,7 +1374,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
             catch_unwind: None,
             timing,
             is_user_relevant: ecx.machine.is_user_relevant(&frame),
-            salt: ecx.machine.rng.borrow_mut().gen::<usize>() % ADDRS_PER_CONST,
+            salt: ecx.machine.rng.borrow_mut().gen::<usize>() % ADDRS_PER_ANON_GLOBAL,
         };
 
         Ok(frame.with_extra(extra))
@@ -1446,7 +1445,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         // tracing-tree can autoamtically annotate scope changes, but it gets very confused by our
         // concurrency and what it prints is just plain wrong. So we print our own information
         // instead. (Cc https://github.com/rust-lang/miri/issues/2266)
-        info!("Leaving {}", ecx.frame().instance);
+        info!("Leaving {}", ecx.frame().instance());
         Ok(())
     }
 
@@ -1476,7 +1475,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         // Needs to be done after dropping frame to show up on the right nesting level.
         // (Cc https://github.com/rust-lang/miri/issues/2266)
         if !ecx.active_thread_stack().is_empty() {
-            info!("Continuing in {}", ecx.frame().instance);
+            info!("Continuing in {}", ecx.frame().instance());
         }
         res
     }
@@ -1489,7 +1488,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         let Some(Provenance::Concrete { alloc_id, .. }) = mplace.ptr().provenance else {
             panic!("after_local_allocated should only be called on fresh allocations");
         };
-        let local_decl = &ecx.frame().body.local_decls[local];
+        let local_decl = &ecx.frame().body().local_decls[local];
         let span = local_decl.source_info.span;
         ecx.machine.allocation_spans.borrow_mut().insert(alloc_id, (span, None));
         Ok(())
@@ -1521,4 +1520,45 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
             Entry::Occupied(oe) => Ok(oe.get().clone()),
         }
     }
+
+    fn get_global_alloc_salt(
+        ecx: &InterpCx<'tcx, Self>,
+        instance: Option<ty::Instance<'tcx>>,
+    ) -> usize {
+        let unique = if let Some(instance) = instance {
+            // Functions cannot be identified by pointers, as asm-equal functions can get
+            // deduplicated by the linker (we set the "unnamed_addr" attribute for LLVM) and
+            // functions can be duplicated across crates. We thus generate a new `AllocId` for every
+            // mention of a function. This means that `main as fn() == main as fn()` is false, while
+            // `let x = main as fn(); x == x` is true. However, as a quality-of-life feature it can
+            // be useful to identify certain functions uniquely, e.g. for backtraces. So we identify
+            // whether codegen will actually emit duplicate functions. It does that when they have
+            // non-lifetime generics, or when they can be inlined. All other functions are given a
+            // unique address. This is not a stable guarantee! The `inline` attribute is a hint and
+            // cannot be relied upon for anything. But if we don't do this, the
+            // `__rust_begin_short_backtrace`/`__rust_end_short_backtrace` logic breaks and panic
+            // backtraces look terrible.
+            let is_generic = instance
+                .args
+                .into_iter()
+                .any(|kind| !matches!(kind.unpack(), ty::GenericArgKind::Lifetime(_)));
+            let can_be_inlined = matches!(
+                ecx.tcx.sess.opts.unstable_opts.cross_crate_inline_threshold,
+                InliningThreshold::Always
+            ) || !matches!(
+                ecx.tcx.codegen_fn_attrs(instance.def_id()).inline,
+                InlineAttr::Never
+            );
+            !is_generic && !can_be_inlined
+        } else {
+            // Non-functions are never unique.
+            false
+        };
+        // Always use the same salt if the allocation is unique.
+        if unique {
+            CTFE_ALLOC_SALT
+        } else {
+            ecx.machine.rng.borrow_mut().gen::<usize>() % ADDRS_PER_ANON_GLOBAL
+        }
+    }
 }
diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs
index 24a4b5f26a9..9bb6777a9b0 100644
--- a/src/tools/miri/src/shims/backtrace.rs
+++ b/src/tools/miri/src/shims/backtrace.rs
@@ -46,8 +46,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let mut data = Vec::new();
         for frame in this.active_thread_stack().iter().rev() {
             // Match behavior of debuginfo (`FunctionCx::adjusted_span_and_dbg_scope`).
-            let span = hygiene::walk_chain_collapsed(frame.current_span(), frame.body.span);
-            data.push((frame.instance, span.lo()));
+            let span = hygiene::walk_chain_collapsed(frame.current_span(), frame.body().span);
+            data.push((frame.instance(), span.lo()));
         }
 
         let ptrs: Vec<_> = data
@@ -116,7 +116,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         let ptr = this.read_pointer(ptr)?;
         // Take apart the pointer, we need its pieces. The offset encodes the span.
-        let (alloc_id, offset, _prov) = this.ptr_get_alloc_id(ptr)?;
+        let (alloc_id, offset, _prov) = this.ptr_get_alloc_id(ptr, 0)?;
 
         // This has to be an actual global fn ptr, not a dlsym function.
         let fn_instance = if let Some(GlobalAlloc::Function { instance, .. }) =
diff --git a/src/tools/miri/src/shims/env.rs b/src/tools/miri/src/shims/env.rs
index 7ad395cccb7..6586ea8e48c 100644
--- a/src/tools/miri/src/shims/env.rs
+++ b/src/tools/miri/src/shims/env.rs
@@ -108,4 +108,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             EnvVars::Windows(vars) => vars.get(name),
         }
     }
+
+    fn get_pid(&self) -> u32 {
+        let this = self.eval_context_ref();
+        if this.machine.communicate() { std::process::id() } else { 1000 }
+    }
 }
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index 9004f7efc8b..7f6f63ff5e7 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -278,7 +278,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "miri_get_alloc_id" => {
                 let [ptr] = this.check_shim(abi, Abi::Rust, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
-                let (alloc_id, _, _) = this.ptr_get_alloc_id(ptr).map_err(|_e| {
+                let (alloc_id, _, _) = this.ptr_get_alloc_id(ptr, 0).map_err(|_e| {
                     err_machine_stop!(TerminationInfo::Abort(format!(
                         "pointer passed to `miri_get_alloc_id` must not be dangling, got {ptr:?}"
                     )))
@@ -311,7 +311,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "miri_static_root" => {
                 let [ptr] = this.check_shim(abi, Abi::Rust, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
-                let (alloc_id, offset, _) = this.ptr_get_alloc_id(ptr)?;
+                let (alloc_id, offset, _) = this.ptr_get_alloc_id(ptr, 0)?;
                 if offset != Size::ZERO {
                     throw_unsup_format!(
                         "pointer passed to `miri_static_root` must point to beginning of an allocated block"
@@ -392,7 +392,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         "`miri_promise_symbolic_alignment`: pointer is not actually aligned"
                     );
                 }
-                if let Ok((alloc_id, offset, ..)) = this.ptr_try_get_alloc_id(ptr) {
+                if let Ok((alloc_id, offset, ..)) = this.ptr_try_get_alloc_id(ptr, 0) {
                     let (_size, alloc_align, _kind) = this.get_alloc_info(alloc_id);
                     // If the newly promised alignment is bigger than the native alignment of this
                     // allocation, and bigger than the previously promised alignment, then set it.
@@ -584,8 +584,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let n = Size::from_bytes(this.read_target_usize(n)?);
 
                 // C requires that this must always be a valid pointer (C18 §7.1.4).
-                this.ptr_get_alloc_id(left)?;
-                this.ptr_get_alloc_id(right)?;
+                this.ptr_get_alloc_id(left, 0)?;
+                this.ptr_get_alloc_id(right, 0)?;
 
                 let result = {
                     let left_bytes = this.read_bytes_ptr_strip_provenance(left, n)?;
@@ -612,7 +612,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let val = val as u8;
 
                 // C requires that this must always be a valid pointer (C18 §7.1.4).
-                this.ptr_get_alloc_id(ptr)?;
+                this.ptr_get_alloc_id(ptr, 0)?;
 
                 if let Some(idx) = this
                     .read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(num))?
@@ -622,7 +622,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 {
                     let idx = u64::try_from(idx).unwrap();
                     #[allow(clippy::arithmetic_side_effects)] // idx < num, so this never wraps
-                    let new_ptr = ptr.offset(Size::from_bytes(num - idx - 1), this)?;
+                    let new_ptr = ptr.wrapping_offset(Size::from_bytes(num - idx - 1), this);
                     this.write_pointer(new_ptr, dest)?;
                 } else {
                     this.write_null(dest)?;
@@ -639,14 +639,14 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let val = val as u8;
 
                 // C requires that this must always be a valid pointer (C18 §7.1.4).
-                this.ptr_get_alloc_id(ptr)?;
+                this.ptr_get_alloc_id(ptr, 0)?;
 
                 let idx = this
                     .read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(num))?
                     .iter()
                     .position(|&c| c == val);
                 if let Some(idx) = idx {
-                    let new_ptr = ptr.offset(Size::from_bytes(idx as u64), this)?;
+                    let new_ptr = ptr.wrapping_offset(Size::from_bytes(idx as u64), this);
                     this.write_pointer(new_ptr, dest)?;
                 } else {
                     this.write_null(dest)?;
@@ -681,8 +681,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
                 // C requires that this must always be a valid pointer, even if `n` is zero, so we better check that.
                 // (This is more than Rust requires, so `mem_copy` is not sufficient.)
-                this.ptr_get_alloc_id(ptr_dest)?;
-                this.ptr_get_alloc_id(ptr_src)?;
+                this.ptr_get_alloc_id(ptr_dest, 0)?;
+                this.ptr_get_alloc_id(ptr_src, 0)?;
 
                 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 306dce5edcd..ab705ddccab 100644
--- a/src/tools/miri/src/shims/panic.rs
+++ b/src/tools/miri/src/shims/panic.rs
@@ -25,7 +25,7 @@ pub struct CatchUnwindData<'tcx> {
     /// The `catch_fn` callback to call in case of a panic.
     catch_fn: Pointer,
     /// The `data` argument for that callback.
-    data: Scalar,
+    data: ImmTy<'tcx>,
     /// The return place from the original call to `try`.
     dest: MPlaceTy<'tcx>,
     /// The return block from the original call to `try`.
@@ -48,9 +48,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn handle_miri_start_unwind(&mut self, payload: &OpTy<'tcx>) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
 
-        trace!("miri_start_unwind: {:?}", this.frame().instance);
+        trace!("miri_start_unwind: {:?}", this.frame().instance());
 
-        let payload = this.read_scalar(payload)?;
+        let payload = this.read_immediate(payload)?;
         let thread = this.active_thread_mut();
         thread.panic_payloads.push(payload);
 
@@ -80,7 +80,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Get all the arguments.
         let [try_fn, data, catch_fn] = check_arg_count(args)?;
         let try_fn = this.read_pointer(try_fn)?;
-        let data = this.read_scalar(data)?;
+        let data = this.read_immediate(data)?;
         let catch_fn = this.read_pointer(catch_fn)?;
 
         // Now we make a function call, and pass `data` as first and only argument.
@@ -89,7 +89,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         this.call_function(
             f_instance,
             Abi::Rust,
-            &[data.into()],
+            &[data.clone()],
             None,
             // Directly return to caller.
             StackPopCleanup::Goto { ret, unwind: mir::UnwindAction::Continue },
@@ -124,7 +124,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // and we are unwinding, so we should catch that.
             trace!(
                 "unwinding: found catch_panic frame during unwinding: {:?}",
-                this.frame().instance
+                this.frame().instance()
             );
 
             // We set the return value of `try` to 1, since there was a panic.
@@ -140,7 +140,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.call_function(
                 f_instance,
                 Abi::Rust,
-                &[catch_unwind.data.into(), payload.into()],
+                &[catch_unwind.data, payload],
                 None,
                 // Directly return to caller of `try`.
                 StackPopCleanup::Goto {
@@ -169,7 +169,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         this.call_function(
             panic,
             Abi::Rust,
-            &[msg.to_ref(this)],
+            &[this.mplace_to_ref(&msg)?],
             None,
             StackPopCleanup::Goto { ret: None, unwind },
         )
@@ -188,7 +188,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         this.call_function(
             panic,
             Abi::Rust,
-            &[msg.to_ref(this)],
+            &[this.mplace_to_ref(&msg)?],
             None,
             StackPopCleanup::Goto { ret: None, unwind: mir::UnwindAction::Unreachable },
         )
@@ -207,9 +207,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // Forward to `panic_bounds_check` lang item.
 
                 // First arg: index.
-                let index = this.read_scalar(&this.eval_operand(index, None)?)?;
+                let index = this.read_immediate(&this.eval_operand(index, None)?)?;
                 // Second arg: len.
-                let len = this.read_scalar(&this.eval_operand(len, None)?)?;
+                let len = this.read_immediate(&this.eval_operand(len, None)?)?;
 
                 // Call the lang item.
                 let panic_bounds_check = this.tcx.lang_items().panic_bounds_check_fn().unwrap();
@@ -217,7 +217,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.call_function(
                     panic_bounds_check,
                     Abi::Rust,
-                    &[index.into(), len.into()],
+                    &[index, len],
                     None,
                     StackPopCleanup::Goto { ret: None, unwind },
                 )?;
@@ -226,9 +226,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // Forward to `panic_misaligned_pointer_dereference` lang item.
 
                 // First arg: required.
-                let required = this.read_scalar(&this.eval_operand(required, None)?)?;
+                let required = this.read_immediate(&this.eval_operand(required, None)?)?;
                 // Second arg: found.
-                let found = this.read_scalar(&this.eval_operand(found, None)?)?;
+                let found = this.read_immediate(&this.eval_operand(found, None)?)?;
 
                 // Call the lang item.
                 let panic_misaligned_pointer_dereference =
@@ -238,7 +238,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.call_function(
                     panic_misaligned_pointer_dereference,
                     Abi::Rust,
-                    &[required.into(), found.into()],
+                    &[required, found],
                     None,
                     StackPopCleanup::Goto { ret: None, unwind },
                 )?;
diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs
index e8f906d37e8..ebec1a70c5c 100644
--- a/src/tools/miri/src/shims/time.rs
+++ b/src/tools/miri/src/shims/time.rs
@@ -93,7 +93,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         Ok(Scalar::from_i32(0))
     }
 
-    fn gettimeofday(&mut self, tv_op: &OpTy<'tcx>, tz_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn gettimeofday(
+        &mut self,
+        tv_op: &OpTy<'tcx>,
+        tz_op: &OpTy<'tcx>,
+    ) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         this.assert_target_os_is_unix("gettimeofday");
@@ -106,7 +110,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if !this.ptr_is_null(tz)? {
             let einval = this.eval_libc("EINVAL");
             this.set_last_error(einval)?;
-            return Ok(-1);
+            return Ok(Scalar::from_i32(-1));
         }
 
         let duration = system_time_to_duration(&SystemTime::now())?;
@@ -115,7 +119,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         this.write_int_fields(&[tv_sec.into(), tv_usec.into()], &tv)?;
 
-        Ok(0)
+        Ok(Scalar::from_i32(0))
     }
 
     // The localtime() function shall convert the time in seconds since the Epoch pointed to by
@@ -308,7 +312,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         &mut self,
         req_op: &OpTy<'tcx>,
         _rem: &OpTy<'tcx>, // Signal handlers are not supported, so rem will never be written to.
-    ) -> InterpResult<'tcx, i32> {
+    ) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         this.assert_target_os_is_unix("nanosleep");
@@ -320,7 +324,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             None => {
                 let einval = this.eval_libc("EINVAL");
                 this.set_last_error(einval)?;
-                return Ok(-1);
+                return Ok(Scalar::from_i32(-1));
             }
         };
 
@@ -333,7 +337,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 @timeout = |_this| { Ok(()) }
             ),
         );
-        Ok(0)
+        Ok(Scalar::from_i32(0))
     }
 
     #[allow(non_snake_case)]
diff --git a/src/tools/miri/src/shims/tls.rs b/src/tools/miri/src/shims/tls.rs
index 87074468789..52d83cd7299 100644
--- a/src/tools/miri/src/shims/tls.rs
+++ b/src/tools/miri/src/shims/tls.rs
@@ -315,6 +315,8 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // FIXME: Technically, the reason should be `DLL_PROCESS_DETACH` when the main thread exits
         // but std treats both the same.
         let reason = this.eval_windows("c", "DLL_THREAD_DETACH");
+        let null_ptr =
+            ImmTy::from_scalar(Scalar::null_ptr(this), this.machine.layouts.const_raw_ptr);
 
         // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`.
         // FIXME: `h` should be a handle to the current module and what `pv` should be is unknown
@@ -322,7 +324,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         this.call_function(
             thread_callback,
             Abi::System { unwind: false },
-            &[Scalar::null_ptr(this).into(), reason.into(), Scalar::null_ptr(this).into()],
+            &[null_ptr.clone(), ImmTy::from_scalar(reason, this.machine.layouts.u32), null_ptr],
             None,
             StackPopCleanup::Root { cleanup: true },
         )?;
@@ -343,7 +345,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.call_function(
                 instance,
                 Abi::C { unwind: false },
-                &[data.into()],
+                &[ImmTy::from_scalar(data, this.machine.layouts.mut_raw_ptr)],
                 None,
                 StackPopCleanup::Root { cleanup: true },
             )?;
@@ -380,7 +382,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.call_function(
                 instance,
                 Abi::C { unwind: false },
-                &[ptr.into()],
+                &[ImmTy::from_scalar(ptr, this.machine.layouts.mut_raw_ptr)],
                 None,
                 StackPopCleanup::Root { cleanup: true },
             )?;
diff --git a/src/tools/miri/src/shims/unix/env.rs b/src/tools/miri/src/shims/unix/env.rs
index 405431f4327..54bf3a3ae82 100644
--- a/src/tools/miri/src/shims/unix/env.rs
+++ b/src/tools/miri/src/shims/unix/env.rs
@@ -81,8 +81,10 @@ 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().strict_add(1)), ecx)?;
+        let var_ptr = var_ptr.wrapping_offset(
+            Size::from_bytes(u64::try_from(name.len()).unwrap().strict_add(1)),
+            ecx,
+        );
         Ok(Some(var_ptr))
     }
 
@@ -148,7 +150,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         Ok(var_ptr.unwrap_or_else(Pointer::null))
     }
 
-    fn setenv(&mut self, name_op: &OpTy<'tcx>, value_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn setenv(
+        &mut self,
+        name_op: &OpTy<'tcx>,
+        value_op: &OpTy<'tcx>,
+    ) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
         this.assert_target_os_is_unix("setenv");
 
@@ -169,16 +175,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?;
             }
             this.update_environ()?;
-            Ok(0) // return zero on success
+            Ok(Scalar::from_i32(0)) // return zero on success
         } else {
             // name argument is a null pointer, points to an empty string, or points to a string containing an '=' character.
             let einval = this.eval_libc("EINVAL");
             this.set_last_error(einval)?;
-            Ok(-1)
+            Ok(Scalar::from_i32(-1))
         }
     }
 
-    fn unsetenv(&mut self, name_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn unsetenv(&mut self, name_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
         this.assert_target_os_is_unix("unsetenv");
 
@@ -195,12 +201,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?;
             }
             this.update_environ()?;
-            Ok(0)
+            Ok(Scalar::from_i32(0))
         } else {
             // name argument is a null pointer, points to an empty string, or points to a string containing an '=' character.
             let einval = this.eval_libc("EINVAL");
             this.set_last_error(einval)?;
-            Ok(-1)
+            Ok(Scalar::from_i32(-1))
         }
     }
 
@@ -232,7 +238,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         Ok(Pointer::null())
     }
 
-    fn chdir(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn chdir(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
         this.assert_target_os_is_unix("chdir");
 
@@ -242,16 +248,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.reject_in_isolation("`chdir`", reject_with)?;
             this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
 
-            return Ok(-1);
+            return Ok(Scalar::from_i32(-1));
         }
 
-        match env::set_current_dir(path) {
-            Ok(()) => Ok(0),
-            Err(e) => {
-                this.set_last_error_from_io_error(e)?;
-                Ok(-1)
-            }
-        }
+        let result = env::set_current_dir(path).map(|()| 0);
+        Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
     }
 
     /// Updates the `environ` static.
@@ -270,16 +271,26 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         Ok(())
     }
 
-    fn getpid(&mut self) -> InterpResult<'tcx, i32> {
+    fn getpid(&mut self) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
         this.assert_target_os_is_unix("getpid");
 
-        this.check_no_isolation("`getpid`")?;
-
         // The reason we need to do this wacky of a conversion is because
         // `libc::getpid` returns an i32, however, `std::process::id()` return an u32.
         // So we un-do the conversion that stdlib does and turn it back into an i32.
-        #[allow(clippy::cast_possible_wrap)]
-        Ok(std::process::id() as i32)
+        // In `Scalar` representation, these are the same, so we don't need to anything else.
+        Ok(Scalar::from_u32(this.get_pid()))
+    }
+
+    fn linux_gettid(&mut self) -> InterpResult<'tcx, Scalar> {
+        let this = self.eval_context_ref();
+        this.assert_target_os("linux", "gettid");
+
+        let index = this.machine.threads.active_thread().to_u32();
+
+        // Compute a TID for this thread, ensuring that the main thread has PID == TID.
+        let tid = this.get_pid().strict_add(index);
+
+        Ok(Scalar::from_u32(tid))
     }
 }
diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs
index 8fb046b5e64..1b25ef05769 100644
--- a/src/tools/miri/src/shims/unix/fd.rs
+++ b/src/tools/miri/src/shims/unix/fd.rs
@@ -12,6 +12,13 @@ use rustc_target::abi::Size;
 use crate::shims::unix::*;
 use crate::*;
 
+#[derive(Debug, Clone, Copy, Eq, PartialEq)]
+pub(crate) enum FlockOp {
+    SharedLock { nonblocking: bool },
+    ExclusiveLock { nonblocking: bool },
+    Unlock,
+}
+
 /// Represents an open file descriptor.
 pub trait FileDescription: std::fmt::Debug + Any {
     fn name(&self) -> &'static str;
@@ -36,6 +43,30 @@ pub trait FileDescription: std::fmt::Debug + Any {
         throw_unsup_format!("cannot write to {}", self.name());
     }
 
+    /// Reads as much as possible into the given buffer from a given offset,
+    /// and returns the number of bytes read.
+    fn pread<'tcx>(
+        &mut self,
+        _communicate_allowed: bool,
+        _bytes: &mut [u8],
+        _offset: u64,
+        _ecx: &mut MiriInterpCx<'tcx>,
+    ) -> InterpResult<'tcx, io::Result<usize>> {
+        throw_unsup_format!("cannot pread from {}", self.name());
+    }
+
+    /// Writes as much as possible from the given buffer starting at a given offset,
+    /// and returns the number of bytes written.
+    fn pwrite<'tcx>(
+        &mut self,
+        _communicate_allowed: bool,
+        _bytes: &[u8],
+        _offset: u64,
+        _ecx: &mut MiriInterpCx<'tcx>,
+    ) -> InterpResult<'tcx, io::Result<usize>> {
+        throw_unsup_format!("cannot pwrite to {}", self.name());
+    }
+
     /// Seeks to the given offset (which can be relative to the beginning, end, or current position).
     /// Returns the new position from the start of the stream.
     fn seek<'tcx>(
@@ -53,6 +84,14 @@ pub trait FileDescription: std::fmt::Debug + Any {
         throw_unsup_format!("cannot close {}", self.name());
     }
 
+    fn flock<'tcx>(
+        &self,
+        _communicate_allowed: bool,
+        _op: FlockOp,
+    ) -> InterpResult<'tcx, io::Result<()>> {
+        throw_unsup_format!("cannot flock {}", self.name());
+    }
+
     fn is_tty(&self, _communicate_allowed: bool) -> bool {
         // Most FDs are not tty's and the consequence of a wrong `false` are minor,
         // so we use a default impl here.
@@ -165,11 +204,11 @@ impl FileDescription for NullOutput {
 }
 
 #[derive(Clone, Debug)]
-pub struct FileDescriptor(Rc<RefCell<Box<dyn FileDescription>>>);
+pub struct FileDescriptionRef(Rc<RefCell<Box<dyn FileDescription>>>);
 
-impl FileDescriptor {
-    pub fn new<T: FileDescription>(fd: T) -> Self {
-        FileDescriptor(Rc::new(RefCell::new(Box::new(fd))))
+impl FileDescriptionRef {
+    fn new(fd: impl FileDescription) -> Self {
+        FileDescriptionRef(Rc::new(RefCell::new(Box::new(fd))))
     }
 
     pub fn borrow(&self) -> Ref<'_, dyn FileDescription> {
@@ -193,7 +232,7 @@ impl FileDescriptor {
 /// The file descriptor table
 #[derive(Debug)]
 pub struct FdTable {
-    pub fds: BTreeMap<i32, FileDescriptor>,
+    fds: BTreeMap<i32, FileDescriptionRef>,
 }
 
 impl VisitProvenance for FdTable {
@@ -203,25 +242,30 @@ impl VisitProvenance for FdTable {
 }
 
 impl FdTable {
-    pub(crate) fn new(mute_stdout_stderr: bool) -> FdTable {
-        let mut fds: BTreeMap<_, FileDescriptor> = BTreeMap::new();
-        fds.insert(0i32, FileDescriptor::new(io::stdin()));
+    fn new() -> Self {
+        FdTable { fds: BTreeMap::new() }
+    }
+    pub(crate) fn init(mute_stdout_stderr: bool) -> FdTable {
+        let mut fds = FdTable::new();
+        fds.insert_new(io::stdin());
         if mute_stdout_stderr {
-            fds.insert(1i32, FileDescriptor::new(NullOutput));
-            fds.insert(2i32, FileDescriptor::new(NullOutput));
+            assert_eq!(fds.insert_new(NullOutput), 1);
+            assert_eq!(fds.insert_new(NullOutput), 2);
         } else {
-            fds.insert(1i32, FileDescriptor::new(io::stdout()));
-            fds.insert(2i32, FileDescriptor::new(io::stderr()));
+            assert_eq!(fds.insert_new(io::stdout()), 1);
+            assert_eq!(fds.insert_new(io::stderr()), 2);
         }
-        FdTable { fds }
+        fds
     }
 
-    pub fn insert_fd(&mut self, file_handle: FileDescriptor) -> i32 {
-        self.insert_fd_with_min_fd(file_handle, 0)
+    /// Insert a new file description to the FdTable.
+    pub fn insert_new(&mut self, fd: impl FileDescription) -> i32 {
+        let file_handle = FileDescriptionRef::new(fd);
+        self.insert_ref_with_min_fd(file_handle, 0)
     }
 
-    /// Insert a new FD that is at least `min_fd`.
-    pub fn insert_fd_with_min_fd(&mut self, file_handle: FileDescriptor, min_fd: i32) -> i32 {
+    /// Insert a file description, giving it a file descriptor that is at least `min_fd`.
+    fn insert_ref_with_min_fd(&mut self, file_handle: FileDescriptionRef, min_fd: i32) -> i32 {
         // Find the lowest unused FD, starting from min_fd. If the first such unused FD is in
         // between used FDs, the find_map combinator will return it. If the first such unused FD
         // is after all other used FDs, the find_map combinator will return None, and we will use
@@ -257,12 +301,12 @@ impl FdTable {
         Some(fd.borrow_mut())
     }
 
-    pub fn dup(&self, fd: i32) -> Option<FileDescriptor> {
+    pub fn get_ref(&self, fd: i32) -> Option<FileDescriptionRef> {
         let fd = self.fds.get(&fd)?;
         Some(fd.clone())
     }
 
-    pub fn remove(&mut self, fd: i32) -> Option<FileDescriptor> {
+    pub fn remove(&mut self, fd: i32) -> Option<FileDescriptionRef> {
         self.fds.remove(&fd)
     }
 
@@ -273,33 +317,67 @@ 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> {
+    fn dup(&mut self, old_fd: i32) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
-        let Some(dup_fd) = this.machine.fds.dup(old_fd) else {
-            return this.fd_not_found();
+        let Some(dup_fd) = this.machine.fds.get_ref(old_fd) else {
+            return Ok(Scalar::from_i32(this.fd_not_found()?));
         };
-        Ok(this.machine.fds.insert_fd_with_min_fd(dup_fd, 0))
+        Ok(Scalar::from_i32(this.machine.fds.insert_ref_with_min_fd(dup_fd, 0)))
     }
 
-    fn dup2(&mut self, old_fd: i32, new_fd: i32) -> InterpResult<'tcx, i32> {
+    fn dup2(&mut self, old_fd: i32, new_fd: i32) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
-        let Some(dup_fd) = this.machine.fds.dup(old_fd) else {
-            return this.fd_not_found();
+        let Some(dup_fd) = this.machine.fds.get_ref(old_fd) else {
+            return Ok(Scalar::from_i32(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) {
+            if let Some(file_description) = 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();
+                file_description.close(this.machine.communicate())?.ok();
             }
         }
-        Ok(new_fd)
+        Ok(Scalar::from_i32(new_fd))
+    }
+
+    fn flock(&mut self, fd: i32, op: i32) -> InterpResult<'tcx, Scalar> {
+        let this = self.eval_context_mut();
+        let Some(file_descriptor) = this.machine.fds.get(fd) else {
+            return Ok(Scalar::from_i32(this.fd_not_found()?));
+        };
+
+        // We need to check that there aren't unsupported options in `op`.
+        let lock_sh = this.eval_libc_i32("LOCK_SH");
+        let lock_ex = this.eval_libc_i32("LOCK_EX");
+        let lock_nb = this.eval_libc_i32("LOCK_NB");
+        let lock_un = this.eval_libc_i32("LOCK_UN");
+
+        use FlockOp::*;
+        let parsed_op = if op == lock_sh {
+            SharedLock { nonblocking: false }
+        } else if op == lock_sh | lock_nb {
+            SharedLock { nonblocking: true }
+        } else if op == lock_ex {
+            ExclusiveLock { nonblocking: false }
+        } else if op == lock_ex | lock_nb {
+            ExclusiveLock { nonblocking: true }
+        } else if op == lock_un {
+            Unlock
+        } else {
+            throw_unsup_format!("unsupported flags {:#x}", op);
+        };
+
+        let result = file_descriptor.flock(this.machine.communicate(), parsed_op)?;
+        drop(file_descriptor);
+        // return `0` if flock is successful
+        let result = result.map(|()| 0i32);
+        Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
     }
 
-    fn fcntl(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, i32> {
+    fn fcntl(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         if args.len() < 2 {
@@ -317,11 +395,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // `FD_CLOEXEC` value without checking if the flag is set for the file because `std`
             // always sets this flag when opening a file. However we still need to check that the
             // file itself is open.
-            if this.machine.fds.is_fd(fd) {
-                Ok(this.eval_libc_i32("FD_CLOEXEC"))
+            Ok(Scalar::from_i32(if this.machine.fds.is_fd(fd) {
+                this.eval_libc_i32("FD_CLOEXEC")
             } else {
-                this.fd_not_found()
-            }
+                this.fd_not_found()?
+            }))
         } else if cmd == this.eval_libc_i32("F_DUPFD")
             || cmd == this.eval_libc_i32("F_DUPFD_CLOEXEC")
         {
@@ -337,16 +415,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             let start = this.read_scalar(&args[2])?.to_i32()?;
 
-            match this.machine.fds.dup(fd) {
-                Some(dup_fd) => Ok(this.machine.fds.insert_fd_with_min_fd(dup_fd, start)),
-                None => this.fd_not_found(),
+            match this.machine.fds.get_ref(fd) {
+                Some(dup_fd) =>
+                    Ok(Scalar::from_i32(this.machine.fds.insert_ref_with_min_fd(dup_fd, start))),
+                None => Ok(Scalar::from_i32(this.fd_not_found()?)),
             }
         } else if this.tcx.sess.target.os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC") {
             // Reject if isolation is enabled.
             if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
                 this.reject_in_isolation("`fcntl`", reject_with)?;
                 this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
-                return Ok(-1);
+                return Ok(Scalar::from_i32(-1));
             }
 
             this.ffullsync_fd(fd)
@@ -360,10 +439,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         let fd = this.read_scalar(fd_op)?.to_i32()?;
 
-        let Some(file_descriptor) = this.machine.fds.remove(fd) else {
+        let Some(file_description) = this.machine.fds.remove(fd) else {
             return Ok(Scalar::from_i32(this.fd_not_found()?));
         };
-        let result = file_descriptor.close(this.machine.communicate())?;
+        let result = file_description.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)?))
@@ -380,7 +459,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         Ok((-1).into())
     }
 
-    fn read(&mut self, fd: i32, buf: Pointer, count: u64) -> InterpResult<'tcx, i64> {
+    /// Read data from `fd` into buffer specified by `buf` and `count`.
+    ///
+    /// If `offset` is `None`, reads data from current cursor position associated with `fd`
+    /// and updates cursor position on completion. Otherwise, reads from the specified offset
+    /// and keeps the cursor unchanged.
+    fn read(
+        &mut self,
+        fd: i32,
+        buf: Pointer,
+        count: u64,
+        offset: Option<i128>,
+    ) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         // Isolation check is done via `FileDescriptor` trait.
@@ -398,25 +488,31 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let communicate = this.machine.communicate();
 
         // We temporarily dup the FD to be able to retain mutable access to `this`.
-        let Some(file_descriptor) = this.machine.fds.dup(fd) else {
+        let Some(fd) = this.machine.fds.get_ref(fd) else {
             trace!("read: FD not found");
-            return this.fd_not_found();
+            return Ok(Scalar::from_target_isize(this.fd_not_found()?, this));
         };
 
-        trace!("read: FD mapped to {:?}", file_descriptor);
+        trace!("read: FD mapped to {fd:?}");
         // We want to read at most `count` bytes. We are sure that `count` is not negative
         // because it was a target's `usize`. Also we are sure that its smaller than
         // `usize::MAX` because it is bounded by the host's `isize`.
         let mut bytes = vec![0; usize::try_from(count).unwrap()];
-        // `File::read` never returns a value larger than `count`,
-        // so this cannot fail.
-        let result = file_descriptor
-            .borrow_mut()
-            .read(communicate, &mut bytes, this)?
-            .map(|c| i64::try_from(c).unwrap());
-        drop(file_descriptor);
+        let result = match offset {
+            None => fd.borrow_mut().read(communicate, &mut bytes, this),
+            Some(offset) => {
+                let Ok(offset) = u64::try_from(offset) else {
+                    let einval = this.eval_libc("EINVAL");
+                    this.set_last_error(einval)?;
+                    return Ok(Scalar::from_target_isize(-1, this));
+                };
+                fd.borrow_mut().pread(communicate, &mut bytes, offset, this)
+            }
+        };
+        drop(fd);
 
-        match result {
+        // `File::read` never returns a value larger than `count`, so this cannot fail.
+        match result?.map(|c| i64::try_from(c).unwrap()) {
             Ok(read_bytes) => {
                 // If reading to `bytes` did not fail, we write those bytes to the buffer.
                 // Crucially, if fewer than `bytes.len()` bytes were read, only write
@@ -425,16 +521,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     buf,
                     bytes[..usize::try_from(read_bytes).unwrap()].iter().copied(),
                 )?;
-                Ok(read_bytes)
+                Ok(Scalar::from_target_isize(read_bytes, this))
             }
             Err(e) => {
                 this.set_last_error_from_io_error(e)?;
-                Ok(-1)
+                Ok(Scalar::from_target_isize(-1, this))
             }
         }
     }
 
-    fn write(&mut self, fd: i32, buf: Pointer, count: u64) -> InterpResult<'tcx, i64> {
+    fn write(
+        &mut self,
+        fd: i32,
+        buf: Pointer,
+        count: u64,
+        offset: Option<i128>,
+    ) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         // Isolation check is done via `FileDescriptor` trait.
@@ -451,16 +553,24 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         let bytes = this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(count))?.to_owned();
         // We temporarily dup the FD to be able to retain mutable access to `this`.
-        let Some(file_descriptor) = this.machine.fds.dup(fd) else {
-            return this.fd_not_found();
+        let Some(fd) = this.machine.fds.get_ref(fd) else {
+            return Ok(Scalar::from_target_isize(this.fd_not_found()?, this));
         };
 
-        let result = file_descriptor
-            .borrow_mut()
-            .write(communicate, &bytes, this)?
-            .map(|c| i64::try_from(c).unwrap());
-        drop(file_descriptor);
+        let result = match offset {
+            None => fd.borrow_mut().write(communicate, &bytes, this),
+            Some(offset) => {
+                let Ok(offset) = u64::try_from(offset) else {
+                    let einval = this.eval_libc("EINVAL");
+                    this.set_last_error(einval)?;
+                    return Ok(Scalar::from_target_isize(-1, this));
+                };
+                fd.borrow_mut().pwrite(communicate, &bytes, offset, this)
+            }
+        };
+        drop(fd);
 
-        this.try_unwrap_io_result(result)
+        let result = result?.map(|c| i64::try_from(c).unwrap());
+        Ok(Scalar::from_target_isize(this.try_unwrap_io_result(result)?, this))
     }
 }
diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs
index 3a18d622033..57930f9807d 100644
--- a/src/tools/miri/src/shims/unix/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/foreign_items.rs
@@ -62,13 +62,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "unsetenv" => {
                 let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.unsetenv(name)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "setenv" => {
                 let [name, value, overwrite] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 this.read_scalar(overwrite)?.to_i32()?;
                 let result = this.setenv(name, value)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "getcwd" => {
                 let [buf, size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -78,12 +78,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "chdir" => {
                 let [path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.chdir(path)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(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)?;
+                this.write_scalar(result, dest)?;
             }
 
             // File descriptors
@@ -92,8 +92,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let fd = this.read_scalar(fd)?.to_i32()?;
                 let buf = this.read_pointer(buf)?;
                 let count = this.read_target_usize(count)?;
-                let result = this.read(fd, buf, count)?;
-                this.write_scalar(Scalar::from_target_isize(result, this), dest)?;
+                let result = this.read(fd, buf, count, None)?;
+                this.write_scalar(result, dest)?;
             }
             "write" => {
                 let [fd, buf, n] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -101,9 +101,49 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let buf = this.read_pointer(buf)?;
                 let count = this.read_target_usize(n)?;
                 trace!("Called write({:?}, {:?}, {:?})", fd, buf, count);
-                let result = this.write(fd, buf, count)?;
+                let result = this.write(fd, buf, count, None)?;
                 // Now, `result` is the value we return back to the program.
-                this.write_scalar(Scalar::from_target_isize(result, this), dest)?;
+                this.write_scalar(result, dest)?;
+            }
+            "pread" => {
+                let [fd, buf, count, offset] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let fd = this.read_scalar(fd)?.to_i32()?;
+                let buf = this.read_pointer(buf)?;
+                let count = this.read_target_usize(count)?;
+                let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
+                let result = this.read(fd, buf, count, Some(offset))?;
+                this.write_scalar(result, dest)?;
+            }
+            "pwrite" => {
+                let [fd, buf, n, offset] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let fd = this.read_scalar(fd)?.to_i32()?;
+                let buf = this.read_pointer(buf)?;
+                let count = this.read_target_usize(n)?;
+                let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
+                trace!("Called pwrite({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
+                let result = this.write(fd, buf, count, Some(offset))?;
+                // Now, `result` is the value we return back to the program.
+                this.write_scalar(result, dest)?;
+            }
+            "pread64" => {
+                let [fd, buf, count, offset] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let fd = this.read_scalar(fd)?.to_i32()?;
+                let buf = this.read_pointer(buf)?;
+                let count = this.read_target_usize(count)?;
+                let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off64_t").size)?;
+                let result = this.read(fd, buf, count, Some(offset))?;
+                this.write_scalar(result, dest)?;
+            }
+            "pwrite64" => {
+                let [fd, buf, n, offset] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let fd = this.read_scalar(fd)?.to_i32()?;
+                let buf = this.read_pointer(buf)?;
+                let count = this.read_target_usize(n)?;
+                let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off64_t").size)?;
+                trace!("Called pwrite64({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
+                let result = this.write(fd, buf, count, Some(offset))?;
+                // Now, `result` is the value we return back to the program.
+                this.write_scalar(result, dest)?;
             }
             "close" => {
                 let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -115,20 +155,27 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // in `this.fcntl()`, so we do not use `check_shim` here.
                 this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?;
                 let result = this.fcntl(args)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(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)?;
+                this.write_scalar(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)?;
+                this.write_scalar(result, dest)?;
+            }
+            "flock" => {
+                let [fd, op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let fd = this.read_scalar(fd)?.to_i32()?;
+                let op = this.read_scalar(op)?.to_i32()?;
+                let result = this.flock(fd, op)?;
+                this.write_scalar(result, dest)?;
             }
 
             // File and file system access
@@ -136,32 +183,32 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // `open` is variadic, the third argument is only present when the second argument has O_CREAT (or on linux O_TMPFILE, but miri doesn't support that) set
                 this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?;
                 let result = this.open(args)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "unlink" => {
                 let [path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.unlink(path)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "symlink" => {
                 let [target, linkpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.symlink(target, linkpath)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "rename" => {
                 let [oldpath, newpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.rename(oldpath, newpath)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "mkdir" => {
                 let [path, mode] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.mkdir(path, mode)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "rmdir" => {
                 let [path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.rmdir(path)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "opendir" => {
                 let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -171,7 +218,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "closedir" => {
                 let [dirp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.closedir(dirp)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "lseek64" => {
                 let [fd, offset, whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -208,12 +255,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "fsync" => {
                 let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.fsync(fd)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "fdatasync" => {
                 let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.fdatasync(fd)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "readlink" => {
                 let [pathname, buf, bufsize] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -238,7 +285,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "mkstemp" => {
                 let [template] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.mkstemp(template)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
 
             // Sockets
@@ -254,7 +301,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "gettimeofday" => {
                 let [tv, tz] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.gettimeofday(tv, tz)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "localtime_r" => {
                 let [timep, result_op] = this.check_shim(abi, Abi::C {unwind: false}, link_name, args)?;
@@ -426,23 +473,23 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Synchronization primitives
             "pthread_mutexattr_init" => {
                 let [attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_mutexattr_init(attr)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.pthread_mutexattr_init(attr)?;
+                this.write_null(dest)?;
             }
             "pthread_mutexattr_settype" => {
                 let [attr, kind] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.pthread_mutexattr_settype(attr, kind)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "pthread_mutexattr_destroy" => {
                 let [attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_mutexattr_destroy(attr)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.pthread_mutexattr_destroy(attr)?;
+                this.write_null(dest)?;
             }
             "pthread_mutex_init" => {
                 let [mutex, attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_mutex_init(mutex, attr)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.pthread_mutex_init(mutex, attr)?;
+                this.write_null(dest)?;
             }
             "pthread_mutex_lock" => {
                 let [mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -451,17 +498,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "pthread_mutex_trylock" => {
                 let [mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.pthread_mutex_trylock(mutex)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "pthread_mutex_unlock" => {
                 let [mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.pthread_mutex_unlock(mutex)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "pthread_mutex_destroy" => {
                 let [mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_mutex_destroy(mutex)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.pthread_mutex_destroy(mutex)?;
+                this.write_int(0, dest)?;
             }
             "pthread_rwlock_rdlock" => {
                 let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -470,7 +517,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "pthread_rwlock_tryrdlock" => {
                 let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.pthread_rwlock_tryrdlock(rwlock)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "pthread_rwlock_wrlock" => {
                 let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -479,22 +526,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "pthread_rwlock_trywrlock" => {
                 let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.pthread_rwlock_trywrlock(rwlock)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "pthread_rwlock_unlock" => {
                 let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_rwlock_unlock(rwlock)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.pthread_rwlock_unlock(rwlock)?;
+                this.write_null(dest)?;
             }
             "pthread_rwlock_destroy" => {
                 let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_rwlock_destroy(rwlock)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.pthread_rwlock_destroy(rwlock)?;
+                this.write_null(dest)?;
             }
             "pthread_condattr_init" => {
                 let [attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_condattr_init(attr)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.pthread_condattr_init(attr)?;
+                this.write_null(dest)?;
             }
             "pthread_condattr_setclock" => {
                 let [attr, clock_id] =
@@ -505,28 +552,28 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "pthread_condattr_getclock" => {
                 let [attr, clock_id] =
                     this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_condattr_getclock(attr, clock_id)?;
-                this.write_scalar(result, dest)?;
+                this.pthread_condattr_getclock(attr, clock_id)?;
+                this.write_null(dest)?;
             }
             "pthread_condattr_destroy" => {
                 let [attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_condattr_destroy(attr)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.pthread_condattr_destroy(attr)?;
+                this.write_null(dest)?;
             }
             "pthread_cond_init" => {
                 let [cond, attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_cond_init(cond, attr)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.pthread_cond_init(cond, attr)?;
+                this.write_null(dest)?;
             }
             "pthread_cond_signal" => {
                 let [cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_cond_signal(cond)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.pthread_cond_signal(cond)?;
+                this.write_null(dest)?;
             }
             "pthread_cond_broadcast" => {
                 let [cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_cond_broadcast(cond)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.pthread_cond_broadcast(cond)?;
+                this.write_null(dest)?;
             }
             "pthread_cond_wait" => {
                 let [cond, mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -538,25 +585,25 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             "pthread_cond_destroy" => {
                 let [cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_cond_destroy(cond)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.pthread_cond_destroy(cond)?;
+                this.write_null(dest)?;
             }
 
             // Threading
             "pthread_create" => {
                 let [thread, attr, start, arg] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_create(thread, attr, start, arg)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.pthread_create(thread, attr, start, arg)?;
+                this.write_null(dest)?;
             }
             "pthread_join" => {
                 let [thread, retval] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_join(thread, retval)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.pthread_join(thread, retval)?;
+                this.write_null(dest)?;
             }
             "pthread_detach" => {
                 let [thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.pthread_detach(thread)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.pthread_detach(thread)?;
+                this.write_null(dest)?;
             }
             "pthread_self" => {
                 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -565,13 +612,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             "sched_yield" => {
                 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let result = this.sched_yield()?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.sched_yield()?;
+                this.write_null(dest)?;
             }
             "nanosleep" => {
                 let [req, rem] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.nanosleep(req, rem)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
             "sched_getaffinity" => {
                 // Currently this function does not exist on all Unixes, e.g. on macOS.
@@ -600,23 +647,23 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 if this.ptr_is_null(mask)? {
                     let einval = this.eval_libc("EFAULT");
                     this.set_last_error(einval)?;
-                    this.write_scalar(Scalar::from_i32(-1), dest)?;
+                    this.write_int(-1, dest)?;
                 } else if cpusetsize == 0 || cpusetsize.checked_rem(chunk_size).unwrap() != 0 {
                     // we only copy whole chunks of size_of::<c_ulong>()
                     let einval = this.eval_libc("EINVAL");
                     this.set_last_error(einval)?;
-                    this.write_scalar(Scalar::from_i32(-1), dest)?;
+                    this.write_int(-1, dest)?;
                 } else if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&thread_id) {
                     let cpuset = cpuset.clone();
                     // we only copy whole chunks of size_of::<c_ulong>()
                     let byte_count = Ord::min(cpuset.as_slice().len(), cpusetsize.try_into().unwrap());
                     this.write_bytes_ptr(mask, cpuset.as_slice()[..byte_count].iter().copied())?;
-                    this.write_scalar(Scalar::from_i32(0), dest)?;
+                    this.write_null(dest)?;
                 } else {
                     // The thread whose ID is pid could not be found
                     let einval = this.eval_libc("ESRCH");
                     this.set_last_error(einval)?;
-                    this.write_scalar(Scalar::from_i32(-1), dest)?;
+                    this.write_int(-1, dest)?;
                 }
             }
             "sched_setaffinity" => {
@@ -643,7 +690,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 if this.ptr_is_null(mask)? {
                     let einval = this.eval_libc("EFAULT");
                     this.set_last_error(einval)?;
-                    this.write_scalar(Scalar::from_i32(-1), dest)?;
+                    this.write_int(-1, dest)?;
                 } else {
                     // NOTE: cpusetsize might be smaller than `CpuAffinityMask::CPU_MASK_BYTES`.
                     // Any unspecified bytes are treated as zero here (none of the CPUs are configured).
@@ -655,13 +702,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     match CpuAffinityMask::from_array(this, this.machine.num_cpus, bits_array) {
                         Some(cpuset) => {
                             this.machine.thread_cpu_affinity.insert(thread_id, cpuset);
-                            this.write_scalar(Scalar::from_i32(0), dest)?;
+                            this.write_null(dest)?;
                         }
                         None => {
                             // The intersection between the mask and the available CPUs was empty.
                             let einval = this.eval_libc("EINVAL");
                             this.set_last_error(einval)?;
-                            this.write_scalar(Scalar::from_i32(-1), dest)?;
+                            this.write_int(-1, dest)?;
                         }
                     }
                 }
@@ -719,10 +766,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 if bufsize > 256 {
                     let err = this.eval_libc("EIO");
                     this.set_last_error(err)?;
-                    this.write_scalar(Scalar::from_i32(-1), dest)?;
+                    this.write_int(-1, dest)?;
                 } else {
                     this.gen_random(buf, bufsize)?;
-                    this.write_scalar(Scalar::from_i32(0), dest)?;
+                    this.write_null(dest)?;
                 }
             }
             "getrandom" => {
diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs
index e34aa5c09df..d93374db818 100644
--- a/src/tools/miri/src/shims/unix/fs.rs
+++ b/src/tools/miri/src/shims/unix/fs.rs
@@ -16,7 +16,7 @@ use crate::shims::unix::*;
 use crate::*;
 use shims::time::system_time_to_duration;
 
-use self::fd::FileDescriptor;
+use self::fd::FlockOp;
 
 #[derive(Debug)]
 struct FileHandle {
@@ -49,6 +49,54 @@ impl FileDescription for FileHandle {
         Ok(self.file.write(bytes))
     }
 
+    fn pread<'tcx>(
+        &mut self,
+        communicate_allowed: bool,
+        bytes: &mut [u8],
+        offset: u64,
+        _ecx: &mut MiriInterpCx<'tcx>,
+    ) -> InterpResult<'tcx, io::Result<usize>> {
+        assert!(communicate_allowed, "isolation should have prevented even opening a file");
+        // Emulates pread using seek + read + seek to restore cursor position.
+        // Correctness of this emulation relies on sequential nature of Miri execution.
+        // The closure is used to emulate `try` block, since we "bubble" `io::Error` using `?`.
+        let mut f = || {
+            let cursor_pos = self.file.stream_position()?;
+            self.file.seek(SeekFrom::Start(offset))?;
+            let res = self.file.read(bytes);
+            // Attempt to restore cursor position even if the read has failed
+            self.file
+                .seek(SeekFrom::Start(cursor_pos))
+                .expect("failed to restore file position, this shouldn't be possible");
+            res
+        };
+        Ok(f())
+    }
+
+    fn pwrite<'tcx>(
+        &mut self,
+        communicate_allowed: bool,
+        bytes: &[u8],
+        offset: u64,
+        _ecx: &mut MiriInterpCx<'tcx>,
+    ) -> InterpResult<'tcx, io::Result<usize>> {
+        assert!(communicate_allowed, "isolation should have prevented even opening a file");
+        // Emulates pwrite using seek + write + seek to restore cursor position.
+        // Correctness of this emulation relies on sequential nature of Miri execution.
+        // The closure is used to emulate `try` block, since we "bubble" `io::Error` using `?`.
+        let mut f = || {
+            let cursor_pos = self.file.stream_position()?;
+            self.file.seek(SeekFrom::Start(offset))?;
+            let res = self.file.write(bytes);
+            // Attempt to restore cursor position even if the write has failed
+            self.file
+                .seek(SeekFrom::Start(cursor_pos))
+                .expect("failed to restore file position, this shouldn't be possible");
+            res
+        };
+        Ok(f())
+    }
+
     fn seek<'tcx>(
         &mut self,
         communicate_allowed: bool,
@@ -81,6 +129,97 @@ impl FileDescription for FileHandle {
         }
     }
 
+    fn flock<'tcx>(
+        &self,
+        communicate_allowed: bool,
+        op: FlockOp,
+    ) -> InterpResult<'tcx, io::Result<()>> {
+        assert!(communicate_allowed, "isolation should have prevented even opening a file");
+        #[cfg(target_family = "unix")]
+        {
+            use std::os::fd::AsRawFd;
+
+            use FlockOp::*;
+            // We always use non-blocking call to prevent interpreter from being blocked
+            let (host_op, lock_nb) = match op {
+                SharedLock { nonblocking } => (libc::LOCK_SH | libc::LOCK_NB, nonblocking),
+                ExclusiveLock { nonblocking } => (libc::LOCK_EX | libc::LOCK_NB, nonblocking),
+                Unlock => (libc::LOCK_UN, false),
+            };
+
+            let fd = self.file.as_raw_fd();
+            let ret = unsafe { libc::flock(fd, host_op) };
+            let res = match ret {
+                0 => Ok(()),
+                -1 => {
+                    let err = io::Error::last_os_error();
+                    if !lock_nb && err.kind() == io::ErrorKind::WouldBlock {
+                        throw_unsup_format!("blocking `flock` is not currently supported");
+                    }
+                    Err(err)
+                }
+                ret => panic!("Unexpected return value from flock: {ret}"),
+            };
+            Ok(res)
+        }
+
+        #[cfg(target_family = "windows")]
+        {
+            use std::os::windows::io::AsRawHandle;
+            use windows_sys::Win32::{
+                Foundation::{ERROR_IO_PENDING, ERROR_LOCK_VIOLATION, FALSE, HANDLE, TRUE},
+                Storage::FileSystem::{
+                    LockFileEx, UnlockFile, LOCKFILE_EXCLUSIVE_LOCK, LOCKFILE_FAIL_IMMEDIATELY,
+                },
+            };
+            let fh = self.file.as_raw_handle() as HANDLE;
+
+            use FlockOp::*;
+            let (ret, lock_nb) = match op {
+                SharedLock { nonblocking } | ExclusiveLock { nonblocking } => {
+                    // We always use non-blocking call to prevent interpreter from being blocked
+                    let mut flags = LOCKFILE_FAIL_IMMEDIATELY;
+                    if matches!(op, ExclusiveLock { .. }) {
+                        flags |= LOCKFILE_EXCLUSIVE_LOCK;
+                    }
+                    let ret = unsafe { LockFileEx(fh, flags, 0, !0, !0, &mut std::mem::zeroed()) };
+                    (ret, nonblocking)
+                }
+                Unlock => {
+                    let ret = unsafe { UnlockFile(fh, 0, 0, !0, !0) };
+                    (ret, false)
+                }
+            };
+
+            let res = match ret {
+                TRUE => Ok(()),
+                FALSE => {
+                    let mut err = io::Error::last_os_error();
+                    let code: u32 = err.raw_os_error().unwrap().try_into().unwrap();
+                    if matches!(code, ERROR_IO_PENDING | ERROR_LOCK_VIOLATION) {
+                        if lock_nb {
+                            // The io error mapping does not know about these error codes,
+                            // so we translate it to `WouldBlock` manually.
+                            let desc = format!("LockFileEx wouldblock error: {err}");
+                            err = io::Error::new(io::ErrorKind::WouldBlock, desc);
+                        } else {
+                            throw_unsup_format!("blocking `flock` is not currently supported");
+                        }
+                    }
+                    Err(err)
+                }
+                _ => panic!("Unexpected return value: {ret}"),
+            };
+            Ok(res)
+        }
+
+        #[cfg(not(any(target_family = "unix", target_family = "windows")))]
+        {
+            let _ = op;
+            compile_error!("flock is supported only on UNIX and Windows hosts");
+        }
+    }
+
     fn is_tty(&self, communicate_allowed: bool) -> bool {
         communicate_allowed && self.file.is_terminal()
     }
@@ -256,7 +395,7 @@ fn maybe_sync_file(
 
 impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
 pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
-    fn open(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, i32> {
+    fn open(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, Scalar> {
         if args.len() < 2 {
             throw_ub_format!(
                 "incorrect number of arguments for `open`: got {}, expected at least 2",
@@ -266,7 +405,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         let this = self.eval_context_mut();
 
-        let path = this.read_pointer(&args[0])?;
+        let path_raw = this.read_pointer(&args[0])?;
+        let path = this.read_path_from_c_str(path_raw)?;
         let flag = this.read_scalar(&args[1])?.to_i32()?;
 
         let mut options = OpenOptions::new();
@@ -363,30 +503,51 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // if the flag contains `O_TMPFILE` then we return a graceful error
                 let eopnotsupp = this.eval_libc("EOPNOTSUPP");
                 this.set_last_error(eopnotsupp)?;
-                return Ok(-1);
+                return Ok(Scalar::from_i32(-1));
+            }
+        }
+
+        let o_nofollow = this.eval_libc_i32("O_NOFOLLOW");
+        if flag & o_nofollow == o_nofollow {
+            #[cfg(unix)]
+            {
+                use std::os::unix::fs::OpenOptionsExt;
+                options.custom_flags(libc::O_NOFOLLOW);
             }
+            // Strictly speaking, this emulation is not equivalent to the O_NOFOLLOW flag behavior:
+            // the path could change between us checking it here and the later call to `open`.
+            // But it's good enough for Miri purposes.
+            #[cfg(not(unix))]
+            {
+                // O_NOFOLLOW only fails when the trailing component is a symlink;
+                // the entire rest of the path can still contain symlinks.
+                if path.is_symlink() {
+                    let eloop = this.eval_libc("ELOOP");
+                    this.set_last_error(eloop)?;
+                    return Ok(Scalar::from_i32(-1));
+                }
+            }
+            mirror |= o_nofollow;
         }
+
         // If `flag` is not equal to `mirror`, there is an unsupported option enabled in `flag`,
         // then we throw an error.
         if flag != mirror {
             throw_unsup_format!("unsupported flags {:#x}", flag & !mirror);
         }
 
-        let path = this.read_path_from_c_str(path)?;
-
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`open`", reject_with)?;
             this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
-            return Ok(-1);
+            return Ok(Scalar::from_i32(-1));
         }
 
-        let fd = options.open(path).map(|file| {
-            let fh = &mut this.machine.fds;
-            fh.insert_fd(FileDescriptor::new(FileHandle { file, writable }))
-        });
+        let fd = options
+            .open(path)
+            .map(|file| this.machine.fds.insert_new(FileHandle { file, writable }));
 
-        this.try_unwrap_io_result(fd)
+        Ok(Scalar::from_i32(this.try_unwrap_io_result(fd)?))
     }
 
     fn lseek64(&mut self, fd: i32, offset: i128, whence: i32) -> InterpResult<'tcx, Scalar> {
@@ -415,19 +576,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         let communicate = this.machine.communicate();
 
-        let Some(mut file_descriptor) = this.machine.fds.get_mut(fd) else {
+        let Some(mut file_description) = this.machine.fds.get_mut(fd) else {
             return Ok(Scalar::from_i64(this.fd_not_found()?));
         };
-        let result = file_descriptor
+        let result = file_description
             .seek(communicate, seek_from)?
             .map(|offset| i64::try_from(offset).unwrap());
-        drop(file_descriptor);
+        drop(file_description);
 
         let result = this.try_unwrap_io_result(result)?;
         Ok(Scalar::from_i64(result))
     }
 
-    fn unlink(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn unlink(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?;
@@ -436,18 +597,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`unlink`", reject_with)?;
             this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
-            return Ok(-1);
+            return Ok(Scalar::from_i32(-1));
         }
 
         let result = remove_file(path).map(|_| 0);
-        this.try_unwrap_io_result(result)
+        Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
     }
 
     fn symlink(
         &mut self,
         target_op: &OpTy<'tcx>,
         linkpath_op: &OpTy<'tcx>,
-    ) -> InterpResult<'tcx, i32> {
+    ) -> InterpResult<'tcx, Scalar> {
         #[cfg(unix)]
         fn create_link(src: &Path, dst: &Path) -> std::io::Result<()> {
             std::os::unix::fs::symlink(src, dst)
@@ -467,11 +628,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`symlink`", reject_with)?;
             this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
-            return Ok(-1);
+            return Ok(Scalar::from_i32(-1));
         }
 
         let result = create_link(&target, &linkpath).map(|_| 0);
-        this.try_unwrap_io_result(result)
+        Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
     }
 
     fn macos_fbsd_stat(
@@ -570,7 +731,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         flags_op: &OpTy<'tcx>,    // Should be an `int`
         mask_op: &OpTy<'tcx>,     // Should be an `unsigned int`
         statxbuf_op: &OpTy<'tcx>, // Should be a `struct statx *`
-    ) -> InterpResult<'tcx, i32> {
+    ) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         this.assert_target_os("linux", "statx");
@@ -585,7 +746,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if this.ptr_is_null(statxbuf_ptr)? || this.ptr_is_null(pathname_ptr)? {
             let efault = this.eval_libc("EFAULT");
             this.set_last_error(efault)?;
-            return Ok(-1);
+            return Ok(Scalar::from_i32(-1));
         }
 
         let statxbuf = this.deref_pointer_as(statxbuf_op, this.libc_ty_layout("statx"))?;
@@ -627,7 +788,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.eval_libc("EBADF")
             };
             this.set_last_error(ecode)?;
-            return Ok(-1);
+            return Ok(Scalar::from_i32(-1));
         }
 
         // the `_mask_op` parameter specifies the file information that the caller requested.
@@ -649,7 +810,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         };
         let metadata = match metadata {
             Some(metadata) => metadata,
-            None => return Ok(-1),
+            None => return Ok(Scalar::from_i32(-1)),
         };
 
         // The `mode` field specifies the type of the file and the permissions over the file for
@@ -742,14 +903,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             &this.project_field_named(&statxbuf, "stx_mtime")?,
         )?;
 
-        Ok(0)
+        Ok(Scalar::from_i32(0))
     }
 
     fn rename(
         &mut self,
         oldpath_op: &OpTy<'tcx>,
         newpath_op: &OpTy<'tcx>,
-    ) -> InterpResult<'tcx, i32> {
+    ) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         let oldpath_ptr = this.read_pointer(oldpath_op)?;
@@ -758,7 +919,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if this.ptr_is_null(oldpath_ptr)? || this.ptr_is_null(newpath_ptr)? {
             let efault = this.eval_libc("EFAULT");
             this.set_last_error(efault)?;
-            return Ok(-1);
+            return Ok(Scalar::from_i32(-1));
         }
 
         let oldpath = this.read_path_from_c_str(oldpath_ptr)?;
@@ -768,15 +929,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`rename`", reject_with)?;
             this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
-            return Ok(-1);
+            return Ok(Scalar::from_i32(-1));
         }
 
         let result = rename(oldpath, newpath).map(|_| 0);
 
-        this.try_unwrap_io_result(result)
+        Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
     }
 
-    fn mkdir(&mut self, path_op: &OpTy<'tcx>, mode_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn mkdir(&mut self, path_op: &OpTy<'tcx>, mode_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         #[cfg_attr(not(unix), allow(unused_variables))]
@@ -792,7 +953,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`mkdir`", reject_with)?;
             this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
-            return Ok(-1);
+            return Ok(Scalar::from_i32(-1));
         }
 
         #[cfg_attr(not(unix), allow(unused_mut))]
@@ -808,10 +969,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         let result = builder.create(path).map(|_| 0i32);
 
-        this.try_unwrap_io_result(result)
+        Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
     }
 
-    fn rmdir(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn rmdir(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?;
@@ -820,12 +981,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`rmdir`", reject_with)?;
             this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
-            return Ok(-1);
+            return Ok(Scalar::from_i32(-1));
         }
 
         let result = remove_dir(path).map(|_| 0i32);
 
-        this.try_unwrap_io_result(result)
+        Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
     }
 
     fn opendir(&mut self, name_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
@@ -928,7 +1089,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     &this.ptr_to_mplace(entry, dirent64_layout),
                 )?;
 
-                let name_ptr = entry.offset(Size::from_bytes(d_name_offset), this)?;
+                let name_ptr = entry.wrapping_offset(Size::from_bytes(d_name_offset), this);
                 this.write_bytes_ptr(name_ptr, name_bytes.iter().copied())?;
 
                 Some(entry)
@@ -1075,27 +1236,24 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         }))
     }
 
-    fn closedir(&mut self, dirp_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn closedir(&mut self, dirp_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         let dirp = this.read_target_usize(dirp_op)?;
 
         // Reject if isolation is enabled.
-        if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
+        Ok(Scalar::from_i32(if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`closedir`", reject_with)?;
-            // Set error code as "EBADF" (bad fd)
-            return this.fd_not_found();
-        }
-
-        if let Some(open_dir) = this.machine.dirs.streams.remove(&dirp) {
+            this.fd_not_found()?
+        } else if let Some(open_dir) = this.machine.dirs.streams.remove(&dirp) {
             if let Some(entry) = open_dir.entry {
                 this.deallocate_ptr(entry, None, MiriMemoryKind::Runtime.into())?;
             }
             drop(open_dir);
-            Ok(0)
+            0
         } else {
-            this.fd_not_found()
-        }
+            this.fd_not_found()?
+        }))
     }
 
     fn ftruncate64(&mut self, fd: i32, length: i128) -> InterpResult<'tcx, Scalar> {
@@ -1108,30 +1266,30 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             return Ok(Scalar::from_i32(this.fd_not_found()?));
         }
 
-        let Some(file_descriptor) = this.machine.fds.get(fd) else {
+        let Some(file_description) = this.machine.fds.get(fd) else {
             return Ok(Scalar::from_i32(this.fd_not_found()?));
         };
 
         // FIXME: Support ftruncate64 for all FDs
         let FileHandle { file, writable } =
-            file_descriptor.downcast_ref::<FileHandle>().ok_or_else(|| {
+            file_description.downcast_ref::<FileHandle>().ok_or_else(|| {
                 err_unsup_format!("`ftruncate64` is only supported on file-backed file descriptors")
             })?;
 
         if *writable {
             if let Ok(length) = length.try_into() {
                 let result = file.set_len(length);
-                drop(file_descriptor);
+                drop(file_description);
                 let result = this.try_unwrap_io_result(result.map(|_| 0i32))?;
                 Ok(Scalar::from_i32(result))
             } else {
-                drop(file_descriptor);
+                drop(file_description);
                 let einval = this.eval_libc("EINVAL");
                 this.set_last_error(einval)?;
                 Ok(Scalar::from_i32(-1))
             }
         } else {
-            drop(file_descriptor);
+            drop(file_description);
             // The file is not writable
             let einval = this.eval_libc("EINVAL");
             this.set_last_error(einval)?;
@@ -1139,7 +1297,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         }
     }
 
-    fn fsync(&mut self, fd_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn fsync(&mut self, fd_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         // On macOS, `fsync` (unlike `fcntl(F_FULLFSYNC)`) does not wait for the
         // underlying disk to finish writing. In the interest of host compatibility,
         // we conservatively implement this with `sync_all`, which
@@ -1153,28 +1311,28 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`fsync`", reject_with)?;
             // Set error code as "EBADF" (bad fd)
-            return this.fd_not_found();
+            return Ok(Scalar::from_i32(this.fd_not_found()?));
         }
 
-        return self.ffullsync_fd(fd);
+        self.ffullsync_fd(fd)
     }
 
-    fn ffullsync_fd(&mut self, fd: i32) -> InterpResult<'tcx, i32> {
+    fn ffullsync_fd(&mut self, fd: i32) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
-        let Some(file_descriptor) = this.machine.fds.get(fd) else {
-            return Ok(this.fd_not_found()?);
+        let Some(file_description) = this.machine.fds.get(fd) else {
+            return Ok(Scalar::from_i32(this.fd_not_found()?));
         };
         // Only regular files support synchronization.
         let FileHandle { file, writable } =
-            file_descriptor.downcast_ref::<FileHandle>().ok_or_else(|| {
+            file_description.downcast_ref::<FileHandle>().ok_or_else(|| {
                 err_unsup_format!("`fsync` is only supported on file-backed file descriptors")
             })?;
         let io_result = maybe_sync_file(file, *writable, File::sync_all);
-        drop(file_descriptor);
-        this.try_unwrap_io_result(io_result)
+        drop(file_description);
+        Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?))
     }
 
-    fn fdatasync(&mut self, fd_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn fdatasync(&mut self, fd_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         let fd = this.read_scalar(fd_op)?.to_i32()?;
@@ -1183,20 +1341,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`fdatasync`", reject_with)?;
             // Set error code as "EBADF" (bad fd)
-            return this.fd_not_found();
+            return Ok(Scalar::from_i32(this.fd_not_found()?));
         }
 
-        let Some(file_descriptor) = this.machine.fds.get(fd) else {
-            return Ok(this.fd_not_found()?);
+        let Some(file_description) = this.machine.fds.get(fd) else {
+            return Ok(Scalar::from_i32(this.fd_not_found()?));
         };
         // Only regular files support synchronization.
         let FileHandle { file, writable } =
-            file_descriptor.downcast_ref::<FileHandle>().ok_or_else(|| {
+            file_description.downcast_ref::<FileHandle>().ok_or_else(|| {
                 err_unsup_format!("`fdatasync` is only supported on file-backed file descriptors")
             })?;
         let io_result = maybe_sync_file(file, *writable, File::sync_data);
-        drop(file_descriptor);
-        this.try_unwrap_io_result(io_result)
+        drop(file_description);
+        Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?))
     }
 
     fn sync_file_range(
@@ -1234,18 +1392,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             return Ok(Scalar::from_i32(this.fd_not_found()?));
         }
 
-        let Some(file_descriptor) = this.machine.fds.get(fd) else {
+        let Some(file_description) = this.machine.fds.get(fd) else {
             return Ok(Scalar::from_i32(this.fd_not_found()?));
         };
         // Only regular files support synchronization.
         let FileHandle { file, writable } =
-            file_descriptor.downcast_ref::<FileHandle>().ok_or_else(|| {
+            file_description.downcast_ref::<FileHandle>().ok_or_else(|| {
                 err_unsup_format!(
                     "`sync_data_range` is only supported on file-backed file descriptors"
                 )
             })?;
         let io_result = maybe_sync_file(file, *writable, File::sync_data);
-        drop(file_descriptor);
+        drop(file_description);
         Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?))
     }
 
@@ -1373,7 +1531,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
         }
     }
-    fn mkstemp(&mut self, template_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn mkstemp(&mut self, template_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         use rand::seq::SliceRandom;
 
         // POSIX defines the template string.
@@ -1404,7 +1562,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.reject_in_isolation("`mkstemp`", reject_with)?;
             let eacc = this.eval_libc("EACCES");
             this.set_last_error(eacc)?;
-            return Ok(-1);
+            return Ok(Scalar::from_i32(-1));
         }
 
         // Get the bytes of the suffix we expect in _target_ encoding.
@@ -1422,7 +1580,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if last_six_char_bytes != suffix_bytes {
             let einval = this.eval_libc("EINVAL");
             this.set_last_error(einval)?;
-            return Ok(-1);
+            return Ok(Scalar::from_i32(-1));
         }
 
         // At this point we know we have 6 ASCII 'X' characters as a suffix.
@@ -1476,10 +1634,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             match file {
                 Ok(f) => {
-                    let fh = &mut this.machine.fds;
-                    let fd =
-                        fh.insert_fd(FileDescriptor::new(FileHandle { file: f, writable: true }));
-                    return Ok(fd);
+                    let fd = this.machine.fds.insert_new(FileHandle { file: f, writable: true });
+                    return Ok(Scalar::from_i32(fd));
                 }
                 Err(e) =>
                     match e.kind() {
@@ -1490,7 +1646,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                             // "On error, -1 is returned, and errno is set to
                             // indicate the error"
                             this.set_last_error_from_io_error(e)?;
-                            return Ok(-1);
+                            return Ok(Scalar::from_i32(-1));
                         }
                     },
             }
@@ -1499,7 +1655,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // We ran out of attempts to create the file, return an error.
         let eexist = this.eval_libc("EEXIST");
         this.set_last_error(eexist)?;
-        Ok(-1)
+        Ok(Scalar::from_i32(-1))
     }
 }
 
@@ -1543,11 +1699,11 @@ impl FileMetadata {
         ecx: &mut MiriInterpCx<'tcx>,
         fd: i32,
     ) -> InterpResult<'tcx, Option<FileMetadata>> {
-        let Some(file_descriptor) = ecx.machine.fds.get(fd) else {
+        let Some(file_description) = ecx.machine.fds.get(fd) else {
             return ecx.fd_not_found().map(|_: i32| None);
         };
 
-        let file = &file_descriptor
+        let file = &file_description
             .downcast_ref::<FileHandle>()
             .ok_or_else(|| {
                 err_unsup_format!(
@@ -1557,7 +1713,7 @@ impl FileMetadata {
             .file;
 
         let metadata = file.metadata();
-        drop(file_descriptor);
+        drop(file_description);
         FileMetadata::from_meta(ecx, metadata)
     }
 
diff --git a/src/tools/miri/src/shims/unix/linux/epoll.rs b/src/tools/miri/src/shims/unix/linux/epoll.rs
index a5661460e95..9127db3d004 100644
--- a/src/tools/miri/src/shims/unix/linux/epoll.rs
+++ b/src/tools/miri/src/shims/unix/linux/epoll.rs
@@ -5,8 +5,6 @@ use rustc_data_structures::fx::FxHashMap;
 use crate::shims::unix::*;
 use crate::*;
 
-use self::shims::unix::fd::FileDescriptor;
-
 /// An `Epoll` file descriptor connects file handles and epoll events
 #[derive(Clone, Debug, Default)]
 struct Epoll {
@@ -66,7 +64,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             );
         }
 
-        let fd = this.machine.fds.insert_fd(FileDescriptor::new(Epoll::default()));
+        let fd = this.machine.fds.insert_new(Epoll::default());
         Ok(Scalar::from_i32(fd))
     }
 
diff --git a/src/tools/miri/src/shims/unix/linux/eventfd.rs b/src/tools/miri/src/shims/unix/linux/eventfd.rs
index cae5abca3bd..4ab8760d930 100644
--- a/src/tools/miri/src/shims/unix/linux/eventfd.rs
+++ b/src/tools/miri/src/shims/unix/linux/eventfd.rs
@@ -8,8 +8,6 @@ use rustc_target::abi::Endian;
 use crate::shims::unix::*;
 use crate::{concurrency::VClock, *};
 
-use self::shims::unix::fd::FileDescriptor;
-
 // We'll only do reads and writes in chunks of size u64.
 const U64_ARRAY_SIZE: usize = mem::size_of::<u64>();
 
@@ -180,11 +178,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             throw_unsup_format!("eventfd: encountered unknown unsupported flags {:#x}", flags);
         }
 
-        let fd = this.machine.fds.insert_fd(FileDescriptor::new(Event {
+        let fd = this.machine.fds.insert_new(Event {
             counter: val.into(),
             is_nonblock,
             clock: VClock::default(),
-        }));
+        });
         Ok(Scalar::from_i32(fd))
     }
 }
diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
index 95bee38cd78..581f0db42e1 100644
--- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
@@ -44,7 +44,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let [dirfd, pathname, flags, mask, statxbuf] =
                     this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let result = this.linux_statx(dirfd, pathname, flags, mask, statxbuf)?;
-                this.write_scalar(Scalar::from_i32(result), dest)?;
+                this.write_scalar(result, dest)?;
             }
 
             // epoll, eventfd
@@ -94,6 +94,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 )?;
                 this.write_scalar(res, dest)?;
             }
+            "gettid" => {
+                let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let result = this.linux_gettid()?;
+                this.write_scalar(result, dest)?;
+            }
 
             // Dynamically invoked syscalls
             "syscall" => {
@@ -171,12 +176,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "__libc_current_sigrtmin" => {
                 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
 
-                this.write_scalar(Scalar::from_i32(SIGRTMIN), dest)?;
+                this.write_int(SIGRTMIN, dest)?;
             }
             "__libc_current_sigrtmax" => {
                 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
 
-                this.write_scalar(Scalar::from_i32(SIGRTMAX), dest)?;
+                this.write_int(SIGRTMAX, dest)?;
             }
 
             // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
diff --git a/src/tools/miri/src/shims/unix/linux/mem.rs b/src/tools/miri/src/shims/unix/linux/mem.rs
index c430eff0180..3b32612e8ba 100644
--- a/src/tools/miri/src/shims/unix/linux/mem.rs
+++ b/src/tools/miri/src/shims/unix/linux/mem.rs
@@ -53,7 +53,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // We just allocated this, the access is definitely in-bounds and fits into our address space.
             // mmap guarantees new mappings are zero-init.
             this.write_bytes_ptr(
-                ptr.offset(Size::from_bytes(old_size), this).unwrap().into(),
+                ptr.wrapping_offset(Size::from_bytes(old_size), this).into(),
                 std::iter::repeat(0u8).take(usize::try_from(increase).unwrap()),
             )
             .unwrap();
diff --git a/src/tools/miri/src/shims/unix/socket.rs b/src/tools/miri/src/shims/unix/socket.rs
index 6d3d63b4efa..455820a9e6e 100644
--- a/src/tools/miri/src/shims/unix/socket.rs
+++ b/src/tools/miri/src/shims/unix/socket.rs
@@ -7,8 +7,6 @@ use std::rc::{Rc, Weak};
 use crate::shims::unix::*;
 use crate::{concurrency::VClock, *};
 
-use self::fd::FileDescriptor;
-
 /// The maximum capacity of the socketpair buffer in bytes.
 /// This number is arbitrary as the value can always
 /// be configured in the real system.
@@ -221,9 +219,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         };
 
         let fds = &mut this.machine.fds;
-        let sv0 = fds.insert_fd(FileDescriptor::new(socketpair_0));
+        let sv0 = fds.insert_new(socketpair_0);
+        let sv1 = fds.insert_new(socketpair_1);
         let sv0 = Scalar::from_int(sv0, sv.layout.size);
-        let sv1 = fds.insert_fd(FileDescriptor::new(socketpair_1));
         let sv1 = Scalar::from_int(sv1, sv.layout.size);
 
         this.write_scalar(sv0, &sv)?;
diff --git a/src/tools/miri/src/shims/unix/sync.rs b/src/tools/miri/src/shims/unix/sync.rs
index e8653117ae9..0b889b11822 100644
--- a/src/tools/miri/src/shims/unix/sync.rs
+++ b/src/tools/miri/src/shims/unix/sync.rs
@@ -363,20 +363,20 @@ fn cond_set_clock_id<'tcx>(
 
 impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
 pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
-    fn pthread_mutexattr_init(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn pthread_mutexattr_init(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
         let default_kind = this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT");
         mutexattr_set_kind(this, attr_op, default_kind)?;
 
-        Ok(0)
+        Ok(())
     }
 
     fn pthread_mutexattr_settype(
         &mut self,
         attr_op: &OpTy<'tcx>,
         kind_op: &OpTy<'tcx>,
-    ) -> InterpResult<'tcx, i32> {
+    ) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         let kind = this.read_scalar(kind_op)?.to_i32()?;
@@ -407,13 +407,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             mutexattr_set_kind(this, attr_op, kind)?;
         } else {
             let einval = this.eval_libc_i32("EINVAL");
-            return Ok(einval);
+            return Ok(Scalar::from_i32(einval));
         }
 
-        Ok(0)
+        Ok(Scalar::from_i32(0))
     }
 
-    fn pthread_mutexattr_destroy(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn pthread_mutexattr_destroy(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
         // Destroying an uninit pthread_mutexattr is UB, so check to make sure it's not uninit.
@@ -435,14 +435,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             &this.deref_pointer_as(attr_op, this.libc_ty_layout("pthread_mutexattr_t"))?,
         )?;
 
-        Ok(0)
+        Ok(())
     }
 
     fn pthread_mutex_init(
         &mut self,
         mutex_op: &OpTy<'tcx>,
         attr_op: &OpTy<'tcx>,
-    ) -> InterpResult<'tcx, i32> {
+    ) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
         let attr = this.read_pointer(attr_op)?;
@@ -457,7 +457,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         mutex_set_kind(this, mutex_op, kind)?;
 
-        Ok(0)
+        Ok(())
     }
 
     fn pthread_mutex_lock(
@@ -501,25 +501,25 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         Ok(())
     }
 
-    fn pthread_mutex_trylock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn pthread_mutex_trylock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         let kind = mutex_get_kind(this, mutex_op)?;
         let id = mutex_get_id(this, mutex_op)?;
 
-        if this.mutex_is_locked(id) {
+        Ok(Scalar::from_i32(if this.mutex_is_locked(id) {
             let owner_thread = this.mutex_get_owner(id);
             if owner_thread != this.active_thread() {
-                Ok(this.eval_libc_i32("EBUSY"))
+                this.eval_libc_i32("EBUSY")
             } else {
                 if is_mutex_kind_default(this, kind)?
                     || is_mutex_kind_normal(this, kind)?
                     || kind == this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK")
                 {
-                    Ok(this.eval_libc_i32("EBUSY"))
+                    this.eval_libc_i32("EBUSY")
                 } else if kind == this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE") {
                     this.mutex_lock(id);
-                    Ok(0)
+                    0
                 } else {
                     throw_unsup_format!(
                         "called pthread_mutex_trylock on an unsupported type of mutex"
@@ -529,11 +529,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         } else {
             // The mutex is unlocked. Let's lock it.
             this.mutex_lock(id);
-            Ok(0)
-        }
+            0
+        }))
     }
 
-    fn pthread_mutex_unlock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn pthread_mutex_unlock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         let kind = mutex_get_kind(this, mutex_op)?;
@@ -541,7 +541,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         if let Some(_old_locked_count) = this.mutex_unlock(id)? {
             // The mutex was locked by the current thread.
-            Ok(0)
+            Ok(Scalar::from_i32(0))
         } else {
             // The mutex was locked by another thread or not locked at all. See
             // the “Unlock When Not Owner” column in
@@ -557,14 +557,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             } else if kind == this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK")
                 || kind == this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE")
             {
-                Ok(this.eval_libc_i32("EPERM"))
+                Ok(Scalar::from_i32(this.eval_libc_i32("EPERM")))
             } else {
                 throw_unsup_format!("called pthread_mutex_unlock on an unsupported type of mutex");
             }
         }
     }
 
-    fn pthread_mutex_destroy(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn pthread_mutex_destroy(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
         let id = mutex_get_id(this, mutex_op)?;
@@ -583,7 +583,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         )?;
         // FIXME: delete interpreter state associated with this mutex.
 
-        Ok(0)
+        Ok(())
     }
 
     fn pthread_rwlock_rdlock(
@@ -605,16 +605,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         Ok(())
     }
 
-    fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         let id = rwlock_get_id(this, rwlock_op)?;
 
         if this.rwlock_is_write_locked(id) {
-            Ok(this.eval_libc_i32("EBUSY"))
+            Ok(Scalar::from_i32(this.eval_libc_i32("EBUSY")))
         } else {
             this.rwlock_reader_lock(id);
-            Ok(0)
+            Ok(Scalar::from_i32(0))
         }
     }
 
@@ -649,35 +649,33 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         Ok(())
     }
 
-    fn pthread_rwlock_trywrlock(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn pthread_rwlock_trywrlock(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         let id = rwlock_get_id(this, rwlock_op)?;
 
         if this.rwlock_is_locked(id) {
-            Ok(this.eval_libc_i32("EBUSY"))
+            Ok(Scalar::from_i32(this.eval_libc_i32("EBUSY")))
         } else {
             this.rwlock_writer_lock(id);
-            Ok(0)
+            Ok(Scalar::from_i32(0))
         }
     }
 
-    fn pthread_rwlock_unlock(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn pthread_rwlock_unlock(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
         let id = rwlock_get_id(this, rwlock_op)?;
 
         #[allow(clippy::if_same_then_else)]
-        if this.rwlock_reader_unlock(id)? {
-            Ok(0)
-        } else if this.rwlock_writer_unlock(id)? {
-            Ok(0)
+        if this.rwlock_reader_unlock(id)? || this.rwlock_writer_unlock(id)? {
+            Ok(())
         } else {
             throw_ub_format!("unlocked an rwlock that was not locked by the active thread");
         }
     }
 
-    fn pthread_rwlock_destroy(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn pthread_rwlock_destroy(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
         let id = rwlock_get_id(this, rwlock_op)?;
@@ -695,10 +693,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         )?;
         // FIXME: delete interpreter state associated with this rwlock.
 
-        Ok(0)
+        Ok(())
     }
 
-    fn pthread_condattr_init(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn pthread_condattr_init(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
         // no clock attribute on macOS
@@ -710,7 +708,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             condattr_set_clock_id(this, attr_op, default_clock_id)?;
         }
 
-        Ok(0)
+        Ok(())
     }
 
     fn pthread_condattr_setclock(
@@ -737,16 +735,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         &mut self,
         attr_op: &OpTy<'tcx>,
         clk_id_op: &OpTy<'tcx>,
-    ) -> InterpResult<'tcx, Scalar> {
+    ) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
         let clock_id = condattr_get_clock_id(this, attr_op)?;
         this.write_scalar(Scalar::from_i32(clock_id), &this.deref_pointer(clk_id_op)?)?;
 
-        Ok(Scalar::from_i32(0))
+        Ok(())
     }
 
-    fn pthread_condattr_destroy(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn pthread_condattr_destroy(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
         // Destroying an uninit pthread_condattr is UB, so check to make sure it's not uninit.
@@ -761,14 +759,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             &this.deref_pointer_as(attr_op, this.libc_ty_layout("pthread_condattr_t"))?,
         )?;
 
-        Ok(0)
+        Ok(())
     }
 
     fn pthread_cond_init(
         &mut self,
         cond_op: &OpTy<'tcx>,
         attr_op: &OpTy<'tcx>,
-    ) -> InterpResult<'tcx, i32> {
+    ) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
         let attr = this.read_pointer(attr_op)?;
@@ -784,21 +782,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         cond_set_clock_id(this, cond_op, clock_id)?;
 
-        Ok(0)
+        Ok(())
     }
 
-    fn pthread_cond_signal(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn pthread_cond_signal(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
         let id = cond_get_id(this, cond_op)?;
         this.condvar_signal(id)?;
-        Ok(0)
+        Ok(())
     }
 
-    fn pthread_cond_broadcast(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn pthread_cond_broadcast(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
         let id = cond_get_id(this, cond_op)?;
         while this.condvar_signal(id)? {}
-        Ok(0)
+        Ok(())
     }
 
     fn pthread_cond_wait(
@@ -869,7 +867,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         Ok(())
     }
 
-    fn pthread_cond_destroy(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn pthread_cond_destroy(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
         let id = cond_get_id(this, cond_op)?;
@@ -885,6 +883,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         this.write_uninit(&this.deref_pointer_as(cond_op, this.libc_ty_layout("pthread_cond_t"))?)?;
         // FIXME: delete interpreter state associated with this condvar.
 
-        Ok(0)
+        Ok(())
     }
 }
diff --git a/src/tools/miri/src/shims/unix/thread.rs b/src/tools/miri/src/shims/unix/thread.rs
index 6fe331ba623..56e8270aa62 100644
--- a/src/tools/miri/src/shims/unix/thread.rs
+++ b/src/tools/miri/src/shims/unix/thread.rs
@@ -1,5 +1,4 @@
 use crate::*;
-use rustc_middle::ty::layout::LayoutOf;
 use rustc_target::spec::abi::Abi;
 
 impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
@@ -10,7 +9,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         _attr: &OpTy<'tcx>,
         start_routine: &OpTy<'tcx>,
         arg: &OpTy<'tcx>,
-    ) -> InterpResult<'tcx, i32> {
+    ) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
         let thread_info_place = this.deref_pointer_as(thread, this.libc_ty_layout("pthread_t"))?;
@@ -24,17 +23,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             start_routine,
             Abi::C { unwind: false },
             func_arg,
-            this.layout_of(this.tcx.types.usize)?,
+            this.machine.layouts.mut_raw_ptr,
         )?;
 
-        Ok(0)
+        Ok(())
     }
 
-    fn pthread_join(
-        &mut self,
-        thread: &OpTy<'tcx>,
-        retval: &OpTy<'tcx>,
-    ) -> InterpResult<'tcx, i32> {
+    fn pthread_join(&mut self, thread: &OpTy<'tcx>, retval: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
         if !this.ptr_is_null(this.read_pointer(retval)?)? {
@@ -45,10 +40,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let thread_id = this.read_scalar(thread)?.to_int(this.libc_ty_layout("pthread_t").size)?;
         this.join_thread_exclusive(thread_id.try_into().expect("thread ID should fit in u32"))?;
 
-        Ok(0)
+        Ok(())
     }
 
-    fn pthread_detach(&mut self, thread: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
+    fn pthread_detach(&mut self, thread: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
         let thread_id = this.read_scalar(thread)?.to_int(this.libc_ty_layout("pthread_t").size)?;
@@ -57,7 +52,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             /*allow_terminated_joined*/ false,
         )?;
 
-        Ok(0)
+        Ok(())
     }
 
     fn pthread_self(&mut self) -> InterpResult<'tcx, Scalar> {
@@ -113,11 +108,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         Ok(if success { Scalar::from_u32(0) } else { this.eval_libc("ERANGE") })
     }
 
-    fn sched_yield(&mut self) -> InterpResult<'tcx, i32> {
+    fn sched_yield(&mut self) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
         this.yield_active_thread();
 
-        Ok(0)
+        Ok(())
     }
 }
diff --git a/src/tools/miri/src/shims/windows/env.rs b/src/tools/miri/src/shims/windows/env.rs
index ed3eb697986..495df18a6ea 100644
--- a/src/tools/miri/src/shims/windows/env.rs
+++ b/src/tools/miri/src/shims/windows/env.rs
@@ -197,12 +197,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     }
 
     #[allow(non_snake_case)]
-    fn GetCurrentProcessId(&mut self) -> InterpResult<'tcx, u32> {
+    fn GetCurrentProcessId(&mut self) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
         this.assert_target_os("windows", "GetCurrentProcessId");
-        this.check_no_isolation("`GetCurrentProcessId`")?;
 
-        Ok(std::process::id())
+        Ok(Scalar::from_u32(this.get_pid()))
     }
 
     #[allow(non_snake_case)]
diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs
index 71f6a2bc033..f840ba16165 100644
--- a/src/tools/miri/src/shims/windows/foreign_items.rs
+++ b/src/tools/miri/src/shims/windows/foreign_items.rs
@@ -141,7 +141,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "GetCurrentProcessId" => {
                 let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
                 let result = this.GetCurrentProcessId()?;
-                this.write_int(result, dest)?;
+                this.write_scalar(result, dest)?;
             }
 
             // File related shims
@@ -372,7 +372,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?;
 
                 // Return success (`1`).
-                this.write_scalar(Scalar::from_i32(1), dest)?;
+                this.write_int(1, dest)?;
             }
 
             // Access to command-line arguments
@@ -563,7 +563,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let ptr = this.read_pointer(ptr)?;
                 let len = this.read_target_usize(len)?;
                 this.gen_random(ptr, len)?;
-                this.write_scalar(Scalar::from_i32(1), dest)?;
+                this.write_int(1, dest)?;
             }
             "BCryptGenRandom" => {
                 // used by getrandom 0.2
@@ -627,7 +627,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
                 this.CloseHandle(handle)?;
 
-                this.write_scalar(Scalar::from_u32(1), dest)?;
+                this.write_int(1, dest)?;
             }
             "GetModuleFileNameW" => {
                 let [handle, filename, size] =
diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs
index 0bbf2a8e13e..1bd32fce8bd 100644
--- a/src/tools/miri/src/shims/x86/mod.rs
+++ b/src/tools/miri/src/shims/x86/mod.rs
@@ -1178,7 +1178,7 @@ fn pclmulqdq<'tcx>(
         // if the i-th bit in right is set
         if (right & (1 << i)) != 0 {
             // xor result with `left` shifted to the left by i positions
-            result ^= (left as u128) << i;
+            result ^= u128::from(left) << i;
         }
     }
 
diff --git a/src/tools/miri/test_dependencies/Cargo.lock b/src/tools/miri/test_dependencies/Cargo.lock
index d534fdab291..e94bef52952 100644
--- a/src/tools/miri/test_dependencies/Cargo.lock
+++ b/src/tools/miri/test_dependencies/Cargo.lock
@@ -4,9 +4,9 @@ version = 3
 
 [[package]]
 name = "addr2line"
-version = "0.21.0"
+version = "0.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
+checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
 dependencies = [
  "gimli",
 ]
@@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 
 [[package]]
 name = "backtrace"
-version = "0.3.71"
+version = "0.3.73"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d"
+checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a"
 dependencies = [
  "addr2line",
  "cc",
@@ -34,9 +34,9 @@ dependencies = [
 
 [[package]]
 name = "bitflags"
-version = "2.5.0"
+version = "2.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
+checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
 
 [[package]]
 name = "bumpalo"
@@ -46,9 +46,9 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
 
 [[package]]
 name = "cc"
-version = "1.0.96"
+version = "1.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "065a29261d53ba54260972629f9ca6bffa69bac13cd1fed61420f7fa68b9f8bd"
+checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc"
 
 [[package]]
 name = "cfg-if"
@@ -58,12 +58,12 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "errno"
-version = "0.3.8"
+version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
+checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
 dependencies = [
  "libc",
- "windows-sys 0.52.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -85,9 +85,9 @@ dependencies = [
 
 [[package]]
 name = "getrandom"
-version = "0.2.14"
+version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c"
+checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
 dependencies = [
  "cfg-if",
  "js-sys",
@@ -98,9 +98,9 @@ dependencies = [
 
 [[package]]
 name = "gimli"
-version = "0.28.1"
+version = "0.29.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
+checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
 
 [[package]]
 name = "hermit-abi"
@@ -119,46 +119,47 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.154"
+version = "0.2.155"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
+checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.4.13"
+version = "0.4.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
+checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
 
 [[package]]
 name = "log"
-version = "0.4.21"
+version = "0.4.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
+checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
 
 [[package]]
 name = "memchr"
-version = "2.7.2"
+version = "2.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
 
 [[package]]
 name = "miniz_oxide"
-version = "0.7.2"
+version = "0.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
+checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
 dependencies = [
  "adler",
 ]
 
 [[package]]
 name = "mio"
-version = "0.8.11"
+version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
+checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4"
 dependencies = [
+ "hermit-abi",
  "libc",
  "wasi 0.11.0+wasi-snapshot-preview1",
- "windows-sys 0.48.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -166,13 +167,13 @@ name = "miri-test-deps"
 version = "0.1.0"
 dependencies = [
  "getrandom 0.1.16",
- "getrandom 0.2.14",
+ "getrandom 0.2.15",
  "libc",
  "num_cpus",
  "page_size",
  "tempfile",
  "tokio",
- "windows-sys 0.52.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -187,9 +188,9 @@ dependencies = [
 
 [[package]]
 name = "object"
-version = "0.32.2"
+version = "0.36.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
+checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e"
 dependencies = [
  "memchr",
 ]
@@ -218,9 +219,9 @@ checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.81"
+version = "1.0.86"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba"
+checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
 dependencies = [
  "unicode-ident",
 ]
@@ -236,9 +237,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-demangle"
-version = "0.1.23"
+version = "0.1.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
+checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
 
 [[package]]
 name = "rustix"
@@ -250,7 +251,7 @@ dependencies = [
  "errno",
  "libc",
  "linux-raw-sys",
- "windows-sys 0.52.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -269,14 +270,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
 dependencies = [
  "libc",
- "windows-sys 0.52.0",
+ "windows-sys",
 ]
 
 [[package]]
 name = "syn"
-version = "2.0.60"
+version = "2.0.72"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3"
+checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -285,38 +286,38 @@ dependencies = [
 
 [[package]]
 name = "tempfile"
-version = "3.10.1"
+version = "3.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
+checksum = "b8fcd239983515c23a32fb82099f97d0b11b8c72f654ed659363a95c3dad7a53"
 dependencies = [
  "cfg-if",
  "fastrand",
+ "once_cell",
  "rustix",
- "windows-sys 0.52.0",
+ "windows-sys",
 ]
 
 [[package]]
 name = "tokio"
-version = "1.37.0"
+version = "1.39.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787"
+checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1"
 dependencies = [
  "backtrace",
  "libc",
  "mio",
- "num_cpus",
  "pin-project-lite",
  "signal-hook-registry",
  "socket2",
  "tokio-macros",
- "windows-sys 0.48.0",
+ "windows-sys",
 ]
 
 [[package]]
 name = "tokio-macros"
-version = "2.2.0"
+version = "2.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
+checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -419,139 +420,73 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 [[package]]
 name = "windows-sys"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
-dependencies = [
- "windows-targets 0.48.5",
-]
-
-[[package]]
-name = "windows-sys"
 version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
 dependencies = [
- "windows-targets 0.52.5",
+ "windows-targets",
 ]
 
 [[package]]
 name = "windows-targets"
-version = "0.48.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
 dependencies = [
- "windows_aarch64_gnullvm 0.48.5",
- "windows_aarch64_msvc 0.48.5",
- "windows_i686_gnu 0.48.5",
- "windows_i686_msvc 0.48.5",
- "windows_x86_64_gnu 0.48.5",
- "windows_x86_64_gnullvm 0.48.5",
- "windows_x86_64_msvc 0.48.5",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.52.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
-dependencies = [
- "windows_aarch64_gnullvm 0.52.5",
- "windows_aarch64_msvc 0.52.5",
- "windows_i686_gnu 0.52.5",
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
  "windows_i686_gnullvm",
- "windows_i686_msvc 0.52.5",
- "windows_x86_64_gnu 0.52.5",
- "windows_x86_64_gnullvm 0.52.5",
- "windows_x86_64_msvc 0.52.5",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
 ]
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.48.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
-
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.52.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.48.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
-
-[[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.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
 
 [[package]]
 name = "windows_i686_gnullvm"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
-
-[[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.48.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
-
-[[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.48.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.52.5"
+version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs
index 96dd99e8844..39b1c3007cb 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs
@@ -1,11 +1,12 @@
 //@ignore-target-windows: No pthreads on Windows
+//~^ERROR: calling a function with more arguments than it expected
 
 //! The thread function must have exactly one argument.
 
 use std::{mem, ptr};
 
 extern "C" fn thread_start() -> *mut libc::c_void {
-    panic!() //~ ERROR: callee has fewer arguments than expected
+    panic!()
 }
 
 fn main() {
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.stderr
index ca6a05ac7dd..aa67420c753 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.stderr
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.stderr
@@ -1,14 +1,10 @@
-error: Undefined Behavior: callee has fewer arguments than expected
-  --> $DIR/libc_pthread_create_too_few_args.rs:LL:CC
-   |
-LL |     panic!()
-   |     ^^^^^^^^ callee has fewer arguments than expected
+error: Undefined Behavior: calling a function with more arguments than it expected
    |
+   = note: calling a function with more arguments than it expected
+   = note: (no span available)
    = 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 on thread `unnamed-ID`:
-   = note: inside `thread_start` at RUSTLIB/core/src/panic.rs:LL:CC
-   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 1 previous error
 
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs
index d8fbc68d344..fc2ab71dff7 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs
@@ -1,11 +1,12 @@
 //@ignore-target-windows: No pthreads on Windows
+//~^ERROR: calling a function with fewer arguments than it requires
 
 //! The thread function must have exactly one argument.
 
 use std::{mem, ptr};
 
 extern "C" fn thread_start(_null: *mut libc::c_void, _x: i32) -> *mut libc::c_void {
-    panic!() //~ ERROR: callee has more arguments than expected
+    panic!()
 }
 
 fn main() {
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.stderr
index 6ab48a76666..4de947b1694 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.stderr
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.stderr
@@ -1,14 +1,10 @@
-error: Undefined Behavior: callee has more arguments than expected
-  --> $DIR/libc_pthread_create_too_many_args.rs:LL:CC
-   |
-LL |     panic!()
-   |     ^^^^^^^^ callee has more arguments than expected
+error: Undefined Behavior: calling a function with fewer arguments than it requires
    |
+   = note: calling a function with fewer arguments than it requires
+   = note: (no span available)
    = 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 on thread `unnamed-ID`:
-   = note: inside `thread_start` at RUSTLIB/core/src/panic.rs:LL:CC
-   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 1 previous error
 
diff --git a/src/tools/miri/tests/fail-dep/libc/affinity.stderr b/src/tools/miri/tests/fail-dep/libc/affinity.stderr
index c01f15800fa..38414623ccb 100644
--- a/src/tools/miri/tests/fail-dep/libc/affinity.stderr
+++ b/src/tools/miri/tests/fail-dep/libc/affinity.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: memory access failed: ALLOC has size 128, so pointer to 129 bytes starting at offset 0 is out-of-bounds
+error: Undefined Behavior: memory access failed: expected a pointer to 129 bytes of memory, but got ALLOC which is only 128 bytes from the end of the allocation
   --> $DIR/affinity.rs:LL:CC
    |
 LL |     let err = unsafe { sched_setaffinity(PID, size_of::<cpu_set_t>() + 1, &cpuset) };
-   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has size 128, so pointer to 129 bytes starting at offset 0 is out-of-bounds
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 129 bytes of memory, but got ALLOC which is only 128 bytes from the end of the allocation
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail-dep/libc/memchr_null.rs b/src/tools/miri/tests/fail-dep/libc/memchr_null.rs
index 672cc10cd63..b6b4b62e621 100644
--- a/src/tools/miri/tests/fail-dep/libc/memchr_null.rs
+++ b/src/tools/miri/tests/fail-dep/libc/memchr_null.rs
@@ -3,6 +3,6 @@ use std::ptr;
 // null is explicitly called out as UB in the C docs.
 fn main() {
     unsafe {
-        libc::memchr(ptr::null(), 0, 0); //~ERROR: dangling
+        libc::memchr(ptr::null(), 0, 0); //~ERROR: null pointer
     }
 }
diff --git a/src/tools/miri/tests/fail-dep/libc/memchr_null.stderr b/src/tools/miri/tests/fail-dep/libc/memchr_null.stderr
index b76722f5f8f..f03ae33ed9f 100644
--- a/src/tools/miri/tests/fail-dep/libc/memchr_null.stderr
+++ b/src/tools/miri/tests/fail-dep/libc/memchr_null.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
+error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer
   --> $DIR/memchr_null.rs:LL:CC
    |
 LL |         libc::memchr(ptr::null(), 0, 0);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail-dep/libc/memcmp_null.rs b/src/tools/miri/tests/fail-dep/libc/memcmp_null.rs
index 066af4a8ae3..0e204aa7f09 100644
--- a/src/tools/miri/tests/fail-dep/libc/memcmp_null.rs
+++ b/src/tools/miri/tests/fail-dep/libc/memcmp_null.rs
@@ -3,6 +3,6 @@ use std::ptr;
 // null is explicitly called out as UB in the C docs.
 fn main() {
     unsafe {
-        libc::memcmp(ptr::null(), ptr::null(), 0); //~ERROR: dangling
+        libc::memcmp(ptr::null(), ptr::null(), 0); //~ERROR: null pointer
     }
 }
diff --git a/src/tools/miri/tests/fail-dep/libc/memcmp_null.stderr b/src/tools/miri/tests/fail-dep/libc/memcmp_null.stderr
index 5c6ba4fd979..4bca5a3db07 100644
--- a/src/tools/miri/tests/fail-dep/libc/memcmp_null.stderr
+++ b/src/tools/miri/tests/fail-dep/libc/memcmp_null.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
+error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer
   --> $DIR/memcmp_null.rs:LL:CC
    |
 LL |         libc::memcmp(ptr::null(), ptr::null(), 0);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail-dep/libc/memcmp_zero.stderr b/src/tools/miri/tests/fail-dep/libc/memcmp_zero.stderr
index 4ab37ab569f..6adaaeb3dbf 100644
--- a/src/tools/miri/tests/fail-dep/libc/memcmp_zero.stderr
+++ b/src/tools/miri/tests/fail-dep/libc/memcmp_zero.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer use: 0x2a[noalloc] is a dangling pointer (it has no provenance)
+error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance)
   --> $DIR/memcmp_zero.rs:LL:CC
    |
 LL |         libc::memcmp(ptr.cast(), ptr.cast(), 0);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: 0x2a[noalloc] is a dangling pointer (it has no provenance)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance)
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail-dep/libc/memcpy_zero.stderr b/src/tools/miri/tests/fail-dep/libc/memcpy_zero.stderr
index 3e1ee7b86e3..b2da332df21 100644
--- a/src/tools/miri/tests/fail-dep/libc/memcpy_zero.stderr
+++ b/src/tools/miri/tests/fail-dep/libc/memcpy_zero.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer use: 0x17[noalloc] is a dangling pointer (it has no provenance)
+error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got 0x17[noalloc] which is a dangling pointer (it has no provenance)
   --> $DIR/memcpy_zero.rs:LL:CC
    |
 LL |         libc::memcpy(to.cast(), from.cast(), 0);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: 0x17[noalloc] is a dangling pointer (it has no provenance)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got 0x17[noalloc] which is a dangling pointer (it has no provenance)
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail-dep/libc/memrchr_null.rs b/src/tools/miri/tests/fail-dep/libc/memrchr_null.rs
index f06336b1299..1fe637d6ce7 100644
--- a/src/tools/miri/tests/fail-dep/libc/memrchr_null.rs
+++ b/src/tools/miri/tests/fail-dep/libc/memrchr_null.rs
@@ -6,6 +6,6 @@ use std::ptr;
 // null is explicitly called out as UB in the C docs.
 fn main() {
     unsafe {
-        libc::memrchr(ptr::null(), 0, 0); //~ERROR: dangling
+        libc::memrchr(ptr::null(), 0, 0); //~ERROR: null pointer
     }
 }
diff --git a/src/tools/miri/tests/fail-dep/libc/memrchr_null.stderr b/src/tools/miri/tests/fail-dep/libc/memrchr_null.stderr
index 0cc7ac19feb..a9ed58d61bb 100644
--- a/src/tools/miri/tests/fail-dep/libc/memrchr_null.stderr
+++ b/src/tools/miri/tests/fail-dep/libc/memrchr_null.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
+error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer
   --> $DIR/memrchr_null.rs:LL:CC
    |
 LL |         libc::memrchr(ptr::null(), 0, 0);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail-dep/tokio/sleep.stderr b/src/tools/miri/tests/fail-dep/tokio/sleep.stderr
index 4b12729bbff..6d19faab905 100644
--- a/src/tools/miri/tests/fail-dep/tokio/sleep.stderr
+++ b/src/tools/miri/tests/fail-dep/tokio/sleep.stderr
@@ -2,7 +2,7 @@ error: unsupported operation: returning ready events from epoll_wait is not yet
   --> CARGO_REGISTRY/.../epoll.rs:LL:CC
    |
 LL | /         syscall!(epoll_wait(
-LL | |             self.ep,
+LL | |             self.ep.as_raw_fd(),
 LL | |             events.as_mut_ptr(),
 LL | |             events.capacity() as i32,
 LL | |             timeout,
diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.rs b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.rs
index 424aace239a..49de3dd0b10 100644
--- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.rs
+++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.rs
@@ -1,6 +1,6 @@
 //@revisions: stack tree
 //@[tree]compile-flags: -Zmiri-tree-borrows
-//@error-in-other-file: pointer to 4 bytes starting at offset 0 is out-of-bounds
+//@error-in-other-file: expected a pointer to 4 bytes of memory
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr
index be01c5cc840..64bbbfcd848 100644
--- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr
+++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer use: ALLOC has size 2, so pointer to 4 bytes starting at offset 0 is out-of-bounds
+error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got ALLOC which is only 2 bytes from the end of the allocation
   --> RUSTLIB/alloc/src/boxed.rs:LL:CC
    |
 LL |         Box(unsafe { Unique::new_unchecked(raw) }, alloc)
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: ALLOC has size 2, so pointer to 4 bytes starting at offset 0 is out-of-bounds
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got ALLOC which is only 2 bytes from the end of the allocation
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr
index be01c5cc840..64bbbfcd848 100644
--- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr
+++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer use: ALLOC has size 2, so pointer to 4 bytes starting at offset 0 is out-of-bounds
+error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got ALLOC which is only 2 bytes from the end of the allocation
   --> RUSTLIB/alloc/src/boxed.rs:LL:CC
    |
 LL |         Box(unsafe { Unique::new_unchecked(raw) }, alloc)
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: ALLOC has size 2, so pointer to 4 bytes starting at offset 0 is out-of-bounds
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got ALLOC which is only 2 bytes from the end of the allocation
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr
index e96e641bb0d..04494b52561 100644
--- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr
+++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer use: 0x4[noalloc] is a dangling pointer (it has no provenance)
+error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x4[noalloc] which is a dangling pointer (it has no provenance)
   --> RUSTLIB/alloc/src/boxed.rs:LL:CC
    |
 LL |         Box(unsafe { Unique::new_unchecked(raw) }, alloc)
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: 0x4[noalloc] is a dangling pointer (it has no provenance)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x4[noalloc] which is a dangling pointer (it has no provenance)
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr
index e96e641bb0d..04494b52561 100644
--- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr
+++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer use: 0x4[noalloc] is a dangling pointer (it has no provenance)
+error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x4[noalloc] which is a dangling pointer (it has no provenance)
   --> RUSTLIB/alloc/src/boxed.rs:LL:CC
    |
 LL |         Box(unsafe { Unique::new_unchecked(raw) }, alloc)
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: 0x4[noalloc] is a dangling pointer (it has no provenance)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x4[noalloc] which is a dangling pointer (it has no provenance)
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr
index 37f2bb39557..a5c031b9496 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr
+++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer use: 0x10[noalloc] is a dangling pointer (it has no provenance)
+error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x10[noalloc] which is a dangling pointer (it has no provenance)
   --> $DIR/dangling_pointer_to_raw_pointer.rs:LL:CC
    |
 LL |     unsafe { &(*x).0 as *const i32 }
-   |              ^^^^^^^ out-of-bounds pointer use: 0x10[noalloc] is a dangling pointer (it has no provenance)
+   |              ^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x10[noalloc] which is a dangling pointer (it has no provenance)
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr b/src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr
index 377022fa97f..d989bff4516 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr
+++ b/src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer use: 0x10[noalloc] is a dangling pointer (it has no provenance)
+error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x10[noalloc] which is a dangling pointer (it has no provenance)
   --> $DIR/deref-invalid-ptr.rs:LL:CC
    |
 LL |     let _y = unsafe { &*x as *const u32 };
-   |                       ^^^ out-of-bounds pointer use: 0x10[noalloc] is a dangling pointer (it has no provenance)
+   |                       ^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x10[noalloc] which is a dangling pointer (it has no provenance)
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.rs b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.rs
index a0773c63cf6..dee05952a99 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.rs
+++ b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.rs
@@ -1,5 +1,5 @@
 #[allow(deref_nullptr)]
 fn main() {
-    let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR: null pointer is a dangling pointer
+    let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR: null pointer
     panic!("this should never print: {}", x);
 }
diff --git a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.stderr b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.stderr
index a18f0f20fc0..1b97265eb32 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.stderr
+++ b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance)
+error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got a null pointer
   --> $DIR/null_pointer_deref.rs:LL:CC
    |
 LL |     let x: i32 = unsafe { *std::ptr::null() };
-   |                           ^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
+   |                           ^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got a null pointer
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.rs b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.rs
index 954596f5754..61f5ef572cf 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.rs
+++ b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.rs
@@ -1,4 +1,4 @@
 #[allow(deref_nullptr)]
 fn main() {
-    unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR: null pointer is a dangling pointer
+    unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR: null pointer
 }
diff --git a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.stderr b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.stderr
index 01d4d12a002..3d75e7a0254 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.stderr
+++ b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance)
+error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got a null pointer
   --> $DIR/null_pointer_write.rs:LL:CC
    |
 LL |     unsafe { *std::ptr::null_mut() = 0i32 };
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got a null pointer
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.stderr b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.stderr
index 4195c68d500..4bfac8f9657 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.stderr
+++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to 8 bytes of memory, but got ALLOC which is only 4 bytes from the end of the allocation
   --> $DIR/out_of_bounds_project.rs:LL:CC
    |
 LL |         let _field = addr_of!((*ptr).2);
-   |                      ^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+   |                      ^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 8 bytes of memory, but got ALLOC which is only 4 bytes from the end of the allocation
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.rs b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.rs
index 658fbd16c2e..595a229baa5 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.rs
+++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.rs
@@ -1,6 +1,6 @@
 fn main() {
     let v: Vec<u16> = vec![1, 2];
     // This read is also misaligned. We make sure that the OOB message has priority.
-    let x = unsafe { *v.as_ptr().wrapping_byte_add(5) }; //~ ERROR: out-of-bounds
+    let x = unsafe { *v.as_ptr().wrapping_byte_add(5) }; //~ ERROR: expected a pointer to 2 bytes of memory
     panic!("this should never print: {}", x);
 }
diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr
index 37dbea37ce2..8a774c21bb7 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr
+++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: memory access failed: ALLOC has size 4, so pointer to 2 bytes starting at offset 5 is out-of-bounds
+error: Undefined Behavior: memory access failed: expected a pointer to 2 bytes of memory, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes
   --> $DIR/out_of_bounds_read.rs:LL:CC
    |
 LL |     let x = unsafe { *v.as_ptr().wrapping_byte_add(5) };
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has size 4, so pointer to 2 bytes starting at offset 5 is out-of-bounds
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 2 bytes of memory, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs
index 2ff537b1ffc..054e1c66cc1 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs
+++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs
@@ -1,5 +1,5 @@
 fn main() {
     let mut v: Vec<u16> = vec![1, 2];
     // This read is also misaligned. We make sure that the OOB message has priority.
-    unsafe { *v.as_mut_ptr().wrapping_byte_add(5) = 0 }; //~ ERROR: out-of-bounds
+    unsafe { *v.as_mut_ptr().wrapping_byte_add(5) = 0 }; //~ ERROR: expected a pointer to 2 bytes of memory
 }
diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr
index 97b3f3ebe7b..6ae9f05d173 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr
+++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: memory access failed: ALLOC has size 4, so pointer to 2 bytes starting at offset 5 is out-of-bounds
+error: Undefined Behavior: memory access failed: expected a pointer to 2 bytes of memory, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes
   --> $DIR/out_of_bounds_write.rs:LL:CC
    |
 LL |     unsafe { *v.as_mut_ptr().wrapping_byte_add(5) = 0 };
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has size 4, so pointer to 2 bytes starting at offset 5 is out-of-bounds
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 2 bytes of memory, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr
index 73c3ff1ee05..2d4fbafd8b7 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr
+++ b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer use: $HEX[noalloc] is a dangling pointer (it has no provenance)
+error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
   --> $DIR/storage_dead_dangling.rs:LL:CC
    |
 LL |     let _ref = unsafe { &mut *(LEAK as *mut i32) };
-   |                         ^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: $HEX[noalloc] is a dangling pointer (it has no provenance)
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/dangling_pointers/wild_pointer_deref.stderr b/src/tools/miri/tests/fail/dangling_pointers/wild_pointer_deref.stderr
index b7492a09dd0..1d8eed3d30a 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/wild_pointer_deref.stderr
+++ b/src/tools/miri/tests/fail/dangling_pointers/wild_pointer_deref.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: memory access failed: 0x2c[noalloc] is a dangling pointer (it has no provenance)
+error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got 0x2c[noalloc] which is a dangling pointer (it has no provenance)
   --> $DIR/wild_pointer_deref.rs:LL:CC
    |
 LL |     let x = unsafe { *p };
-   |                      ^^ memory access failed: 0x2c[noalloc] is a dangling pointer (it has no provenance)
+   |                      ^^ memory access failed: expected a pointer to 4 bytes of memory, but got 0x2c[noalloc] which is a dangling pointer (it has no provenance)
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/extern-type-field-offset.stderr b/src/tools/miri/tests/fail/extern-type-field-offset.stderr
index 3ed5732b4eb..c07b63e0c03 100644
--- a/src/tools/miri/tests/fail/extern-type-field-offset.stderr
+++ b/src/tools/miri/tests/fail/extern-type-field-offset.stderr
@@ -1,3 +1,14 @@
+warning: reborrow of reference to `extern type`
+  --> $DIR/extern-type-field-offset.rs:LL:CC
+   |
+LL |     let x: &Newtype = unsafe { &*(&buf as *const _ as *const Newtype) };
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reborrow of a reference to `extern type` is not properly supported
+   |
+   = help: `extern type` are not compatible with the Stacked Borrows aliasing model implemented by Miri; Miri may miss bugs in this code
+   = help: try running with `MIRIFLAGS=-Zmiri-tree-borrows` to use the more permissive but also even more experimental Tree Borrows aliasing checks instead
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/extern-type-field-offset.rs:LL:CC
+
 error: unsupported operation: `extern type` field does not have a known offset
   --> $DIR/extern-type-field-offset.rs:LL:CC
    |
@@ -10,5 +21,5 @@ LL |     let _field = &x.a;
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
-error: aborting due to 1 previous error
+error: aborting due to 1 previous error; 1 warning emitted
 
diff --git a/src/tools/miri/tests/fail/function_calls/check_callback_abi.rs b/src/tools/miri/tests/fail/function_calls/check_callback_abi.rs
index fd667fbe454..6a7a26710d1 100644
--- a/src/tools/miri/tests/fail/function_calls/check_callback_abi.rs
+++ b/src/tools/miri/tests/fail/function_calls/check_callback_abi.rs
@@ -9,7 +9,7 @@ fn main() {
         // Make sure we check the ABI when Miri itself invokes a function
         // as part of a shim implementation.
         std::intrinsics::catch_unwind(
-            //~^ ERROR: calling a function with ABI C using caller ABI Rust
+            //~^ ERROR: calling a function with calling convention C using calling convention Rust
             std::mem::transmute::<extern "C" fn(*mut u8), _>(try_fn),
             std::ptr::null_mut(),
             |_, _| unreachable!(),
diff --git a/src/tools/miri/tests/fail/function_calls/check_callback_abi.stderr b/src/tools/miri/tests/fail/function_calls/check_callback_abi.stderr
index 501f17c86d6..890fed09e48 100644
--- a/src/tools/miri/tests/fail/function_calls/check_callback_abi.stderr
+++ b/src/tools/miri/tests/fail/function_calls/check_callback_abi.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: calling a function with ABI C using caller ABI Rust
+error: Undefined Behavior: calling a function with calling convention C using calling convention Rust
   --> $DIR/check_callback_abi.rs:LL:CC
    |
 LL | /         std::intrinsics::catch_unwind(
@@ -7,7 +7,7 @@ LL | |             std::mem::transmute::<extern "C" fn(*mut u8), _>(try_fn),
 LL | |             std::ptr::null_mut(),
 LL | |             |_, _| unreachable!(),
 LL | |         );
-   | |_________^ calling a function with ABI C using caller ABI Rust
+   | |_________^ calling a function with calling convention C using calling convention Rust
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr b/src/tools/miri/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr
index 7274f62b4d7..347afa77053 100644
--- a/src/tools/miri/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr
+++ b/src/tools/miri/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer use: 0x2a[noalloc] is a dangling pointer (it has no provenance)
+error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance)
   --> $DIR/cast_int_to_fn_ptr.rs:LL:CC
    |
 LL |     g(42)
-   |     ^^^^^ out-of-bounds pointer use: 0x2a[noalloc] is a dangling pointer (it has no provenance)
+   |     ^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance)
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_1.rs b/src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_1.rs
deleted file mode 100644
index b6a110ee84d..00000000000
--- a/src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_1.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-fn main() {
-    let v = [0i8; 4];
-    let x = &v as *const i8;
-    // The error is inside another function, so we cannot match it by line
-    let x = unsafe { x.offset(5) }; //~ERROR: pointer to 5 bytes starting at offset 0 is out-of-bounds
-    panic!("this should never print: {:?}", x);
-}
diff --git a/src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_2.stderr b/src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_2.stderr
deleted file mode 100644
index 97fa1f19af1..00000000000
--- a/src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_2.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error: Undefined Behavior: overflowing in-bounds pointer arithmetic
-  --> $DIR/out_of_bounds_ptr_2.rs:LL:CC
-   |
-LL |     let x = unsafe { x.offset(isize::MIN) };
-   |                      ^^^^^^^^^^^^^^^^^^^^ overflowing in-bounds pointer arithmetic
-   |
-   = 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/out_of_bounds_ptr_2.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr
index 217bc82010d..84023cf7937 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,11 +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`, 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 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.
+   = 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 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/intrinsics/ptr_offset_from_different_ints.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs
index 57b4fd0dedb..c307dfddb6c 100644
--- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs
@@ -16,6 +16,6 @@ fn main() {
         let _ = p1.byte_offset_from(p1);
 
         // UB because different pointers.
-        let _ = p1.byte_offset_from(p2); //~ERROR: different pointers without provenance
+        let _ = p1.byte_offset_from(p2); //~ERROR: no provenance
     }
 }
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr
index 6e9e5633fec..bf36c54ac78 100644
--- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `ptr_offset_from` called on different pointers without provenance (i.e., without an associated allocation)
+error: Undefined Behavior: out-of-bounds `offset_from` origin: expected a pointer to the end of 1 byte of memory, but got 0xb[noalloc] which is a dangling pointer (it has no provenance)
   --> $DIR/ptr_offset_from_different_ints.rs:LL:CC
    |
 LL |         let _ = p1.byte_offset_from(p2);
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on different pointers without provenance (i.e., without an associated allocation)
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from` origin: expected a pointer to the end of 1 byte of memory, but got 0xb[noalloc] which is a dangling pointer (it has no provenance)
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs
index 06d13d9bdba..13eb5bfb342 100644
--- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs
@@ -1,8 +1,9 @@
+//@normalize-stderr-test: "\d+ < \d+" -> "$$ADDR < $$ADDR"
 #![feature(ptr_sub_ptr)]
 
 fn main() {
     let arr = [0u8; 8];
     let ptr1 = arr.as_ptr();
     let ptr2 = ptr1.wrapping_add(4);
-    let _val = unsafe { ptr1.sub_ptr(ptr2) }; //~ERROR: first pointer has smaller offset than second: 0 < 4
+    let _val = unsafe { ptr1.sub_ptr(ptr2) }; //~ERROR: first pointer has smaller address than second
 }
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr
index 0b4a9faf1b2..e436f9029d5 100644
--- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: 0 < 4
+error: Undefined Behavior: `ptr_offset_from_unsigned` called when first pointer has smaller address than second: $ADDR < $ADDR
   --> $DIR/ptr_offset_from_unsigned_neg.rs:LL:CC
    |
 LL |     let _val = unsafe { ptr1.sub_ptr(ptr2) };
-   |                         ^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: 0 < 4
+   |                         ^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer has smaller address than second: $ADDR < $ADDR
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr
index e03abfb1a2f..8d37da65061 100644
--- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance)
+error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to 1 byte of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance)
   --> $DIR/ptr_offset_int_plus_int.rs:LL:CC
    |
 LL |         let _val = (1 as *mut u8).offset(1);
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance)
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 1 byte of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance)
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs
index fd3c9b44615..29bf61e25c8 100644
--- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs
@@ -1,4 +1,5 @@
 //@compile-flags: -Zmiri-permissive-provenance
+//@normalize-stderr-test: "\d+ bytes" -> "$$BYTES bytes"
 
 fn main() {
     let ptr = Box::into_raw(Box::new(0u32));
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr
index 03ae9bd141c..2cd02bee2ca 100644
--- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance)
+error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to $BYTES bytes of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance)
   --> $DIR/ptr_offset_int_plus_ptr.rs:LL:CC
    |
 LL |         let _val = (1 as *mut u8).offset(ptr as isize);
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance)
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to $BYTES bytes of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance)
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_2.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.rs
index 0d4eea9a5bd..905fc678f6d 100644
--- a/src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_2.rs
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.rs
@@ -1,6 +1,6 @@
 fn main() {
     let v = [0i8; 4];
     let x = &v as *const i8;
-    let x = unsafe { x.offset(isize::MIN) }; //~ERROR: overflowing in-bounds pointer arithmetic
+    let x = unsafe { x.offset(5) }; //~ERROR: expected a pointer to 5 bytes of memory
     panic!("this should never print: {:?}", x);
 }
diff --git a/src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.stderr
index cc8cca70ddb..c4548200f05 100644
--- a/src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.stderr
@@ -1,18 +1,18 @@
-error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 5 bytes starting at offset 0 is out-of-bounds
-  --> $DIR/out_of_bounds_ptr_1.rs:LL:CC
+error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to 5 bytes of memory, but got ALLOC which is only 4 bytes from the end of the allocation
+  --> $DIR/ptr_offset_out_of_bounds.rs:LL:CC
    |
 LL |     let x = unsafe { x.offset(5) };
-   |                      ^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 5 bytes starting at offset 0 is out-of-bounds
+   |                      ^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 5 bytes of memory, but got ALLOC which is only 4 bytes from the end of the allocation
    |
    = 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: ALLOC was allocated here:
-  --> $DIR/out_of_bounds_ptr_1.rs:LL:CC
+  --> $DIR/ptr_offset_out_of_bounds.rs:LL:CC
    |
 LL |     let v = [0i8; 4];
    |         ^
    = note: BACKTRACE (of the first span):
-   = note: inside `main` at $DIR/out_of_bounds_ptr_1.rs:LL:CC
+   = note: inside `main` at $DIR/ptr_offset_out_of_bounds.rs:LL:CC
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
diff --git a/src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_3.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.rs
index 701bc33a645..bd1d5c064c0 100644
--- a/src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_3.rs
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.rs
@@ -1,6 +1,6 @@
 fn main() {
     let v = [0i8; 4];
     let x = &v as *const i8;
-    let x = unsafe { x.offset(-1) }; //~ERROR: pointer to 1 byte starting at offset -1 is out-of-bounds
+    let x = unsafe { x.offset(-1) }; //~ERROR: expected a pointer to the end of 1 byte of memory
     panic!("this should never print: {:?}", x);
 }
diff --git a/src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.stderr
index 236b51e82e5..8041e1542c6 100644
--- a/src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.stderr
@@ -1,18 +1,18 @@
-error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 1 byte starting at offset -1 is out-of-bounds
-  --> $DIR/out_of_bounds_ptr_3.rs:LL:CC
+error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to the end of 1 byte of memory, but got ALLOC which is at the beginning of the allocation
+  --> $DIR/ptr_offset_out_of_bounds_neg.rs:LL:CC
    |
 LL |     let x = unsafe { x.offset(-1) };
-   |                      ^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 1 byte starting at offset -1 is out-of-bounds
+   |                      ^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to the end of 1 byte of memory, but got ALLOC which is at the beginning of the allocation
    |
    = 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: ALLOC was allocated here:
-  --> $DIR/out_of_bounds_ptr_3.rs:LL:CC
+  --> $DIR/ptr_offset_out_of_bounds_neg.rs:LL:CC
    |
 LL |     let v = [0i8; 4];
    |         ^
    = note: BACKTRACE (of the first span):
-   = note: inside `main` at $DIR/out_of_bounds_ptr_3.rs:LL:CC
+   = note: inside `main` at $DIR/ptr_offset_out_of_bounds_neg.rs:LL:CC
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.rs
index c3db1e23b9b..68394312232 100644
--- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.rs
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.rs
@@ -1,5 +1,8 @@
+//@normalize-stderr-test: "\d+ bytes" -> "$$BYTES bytes"
+
 fn main() {
-    let v = [1i8, 2];
-    let x = &v[1] as *const i8;
-    let _val = unsafe { x.offset(isize::MIN) }; //~ERROR: overflowing in-bounds pointer arithmetic
+    let v = [0i8; 4];
+    let x = &v as *const i8;
+    let x = unsafe { x.offset(isize::MIN) }; //~ERROR: out-of-bounds pointer arithmetic
+    panic!("this should never print: {:?}", x);
 }
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.stderr
index 122529c3049..ee5aebc6eae 100644
--- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.stderr
@@ -1,12 +1,17 @@
-error: Undefined Behavior: overflowing in-bounds pointer arithmetic
+error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to the end of $BYTES bytes of memory, but got ALLOC which is at the beginning of the allocation
   --> $DIR/ptr_offset_overflow.rs:LL:CC
    |
-LL |     let _val = unsafe { x.offset(isize::MIN) };
-   |                         ^^^^^^^^^^^^^^^^^^^^ overflowing in-bounds pointer arithmetic
+LL |     let x = unsafe { x.offset(isize::MIN) };
+   |                      ^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to the end of $BYTES bytes of memory, but got ALLOC which is at the beginning of the allocation
    |
    = 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:
+help: ALLOC was allocated here:
+  --> $DIR/ptr_offset_overflow.rs:LL:CC
+   |
+LL |     let v = [0i8; 4];
+   |         ^
+   = note: BACKTRACE (of the first span):
    = note: inside `main` at $DIR/ptr_offset_overflow.rs:LL:CC
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
diff --git a/src/tools/miri/tests/fail/intrinsics/raw_eq_on_ptr.rs b/src/tools/miri/tests/fail/intrinsics/raw_eq_on_ptr.rs
deleted file mode 100644
index c14f86147db..00000000000
--- a/src/tools/miri/tests/fail/intrinsics/raw_eq_on_ptr.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-#![feature(intrinsics)]
-
-extern "rust-intrinsic" {
-    fn raw_eq<T>(a: &T, b: &T) -> bool;
-}
-
-fn main() {
-    let x = &0;
-    unsafe { raw_eq(&x, &x) }; //~ERROR: `raw_eq` on bytes with provenance
-}
diff --git a/src/tools/miri/tests/fail/intrinsics/raw_eq_on_ptr.stderr b/src/tools/miri/tests/fail/intrinsics/raw_eq_on_ptr.stderr
deleted file mode 100644
index 83f81fa726e..00000000000
--- a/src/tools/miri/tests/fail/intrinsics/raw_eq_on_ptr.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error: Undefined Behavior: `raw_eq` on bytes with provenance
-  --> $DIR/raw_eq_on_ptr.rs:LL:CC
-   |
-LL |     unsafe { raw_eq(&x, &x) };
-   |              ^^^^^^^^^^^^^^ `raw_eq` on bytes with provenance
-   |
-   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
-   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
-   = note: BACKTRACE:
-   = note: inside `main` at $DIR/raw_eq_on_ptr.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/miri/tests/fail/intrinsics/simd-gather.rs b/src/tools/miri/tests/fail/intrinsics/simd-gather.rs
index ceb7beebd8a..b8373952451 100644
--- a/src/tools/miri/tests/fail/intrinsics/simd-gather.rs
+++ b/src/tools/miri/tests/fail/intrinsics/simd-gather.rs
@@ -5,6 +5,7 @@ fn main() {
     unsafe {
         let vec: &[i8] = &[10, 11, 12, 13, 14, 15, 16, 17, 18];
         let idxs = Simd::from_array([9, 3, 0, 17]);
-        let _result = Simd::gather_select_unchecked(&vec, Mask::splat(true), idxs, Simd::splat(0)); //~ERROR: pointer to 1 byte starting at offset 9 is out-of-bounds
+        let _result = Simd::gather_select_unchecked(&vec, Mask::splat(true), idxs, Simd::splat(0));
+        //~^ERROR: expected a pointer to 1 byte of memory
     }
 }
diff --git a/src/tools/miri/tests/fail/intrinsics/simd-gather.stderr b/src/tools/miri/tests/fail/intrinsics/simd-gather.stderr
index d111644eec8..bc8d0b041d3 100644
--- a/src/tools/miri/tests/fail/intrinsics/simd-gather.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/simd-gather.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: memory access failed: ALLOC has size 9, so pointer to 1 byte starting at offset 9 is out-of-bounds
+error: Undefined Behavior: memory access failed: expected a pointer to 1 byte of memory, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes
   --> $DIR/simd-gather.rs:LL:CC
    |
 LL |         let _result = Simd::gather_select_unchecked(&vec, Mask::splat(true), idxs, Simd::splat(0));
-   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has size 9, so pointer to 1 byte starting at offset 9 is out-of-bounds
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/simd-scatter.rs b/src/tools/miri/tests/fail/intrinsics/simd-scatter.rs
index 98b6749c584..bb8c9dbe4c7 100644
--- a/src/tools/miri/tests/fail/intrinsics/simd-scatter.rs
+++ b/src/tools/miri/tests/fail/intrinsics/simd-scatter.rs
@@ -6,7 +6,7 @@ fn main() {
         let mut vec: Vec<i8> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
         let idxs = Simd::from_array([9, 3, 0, 17]);
         Simd::from_array([-27, 82, -41, 124]).scatter_select_unchecked(
-            //~^ERROR: pointer to 1 byte starting at offset 9 is out-of-bounds
+            //~^ERROR: expected a pointer to 1 byte of memory
             &mut vec,
             Mask::splat(true),
             idxs,
diff --git a/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr b/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr
index 8b517b6e972..aae77edcb6b 100644
--- a/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: memory access failed: ALLOC has size 9, so pointer to 1 byte starting at offset 9 is out-of-bounds
+error: Undefined Behavior: memory access failed: expected a pointer to 1 byte of memory, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes
   --> $DIR/simd-scatter.rs:LL:CC
    |
 LL | /         Simd::from_array([-27, 82, -41, 124]).scatter_select_unchecked(
@@ -7,7 +7,7 @@ LL | |             &mut vec,
 LL | |             Mask::splat(true),
 LL | |             idxs,
 LL | |         );
-   | |_________^ memory access failed: ALLOC has size 9, so pointer to 1 byte starting at offset 9 is out-of-bounds
+   | |_________^ memory access failed: expected a pointer to 1 byte of memory, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/miri_start_wrong_sig.rs b/src/tools/miri/tests/fail/miri_start_wrong_sig.rs
new file mode 100644
index 00000000000..dac83d817ba
--- /dev/null
+++ b/src/tools/miri/tests/fail/miri_start_wrong_sig.rs
@@ -0,0 +1,21 @@
+//@compile-flags: -Cpanic=abort
+//@error-in-other-file: `miri_start` must have the following signature:
+#![no_main]
+#![no_std]
+
+use core::fmt::Write;
+
+#[path = "../utils/mod.no_std.rs"]
+mod utils;
+
+#[no_mangle]
+fn miri_start() -> isize {
+    //~^ ERROR: mismatched types
+    writeln!(utils::MiriStdout, "Hello from miri_start!").unwrap();
+    0
+}
+
+#[panic_handler]
+fn panic_handler(_: &core::panic::PanicInfo) -> ! {
+    loop {}
+}
diff --git a/src/tools/miri/tests/fail/miri_start_wrong_sig.stderr b/src/tools/miri/tests/fail/miri_start_wrong_sig.stderr
new file mode 100644
index 00000000000..62171917116
--- /dev/null
+++ b/src/tools/miri/tests/fail/miri_start_wrong_sig.stderr
@@ -0,0 +1,15 @@
+error[E0308]: mismatched types
+  --> $DIR/miri_start_wrong_sig.rs:LL:CC
+   |
+LL | fn miri_start() -> isize {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters
+   |
+   = note: expected signature `fn(isize, *const *const u8) -> _`
+              found signature `fn() -> _`
+
+error: `miri_start` must have the following signature:
+       fn miri_start(argc: isize, argv: *const *const u8) -> isize
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/tools/miri/tests/fail/no_main.rs b/src/tools/miri/tests/fail/no_main.rs
index 01b8c7bd66b..4bbd820a636 100644
--- a/src/tools/miri/tests/fail/no_main.rs
+++ b/src/tools/miri/tests/fail/no_main.rs
@@ -1,2 +1,2 @@
-//@error-in-other-file: miri can only run programs that have a main function
+//@error-in-other-file: Miri can only run programs that have a main function.
 #![no_main]
diff --git a/src/tools/miri/tests/fail/no_main.stderr b/src/tools/miri/tests/fail/no_main.stderr
index 1c4fc88989b..e9b9e5d65b1 100644
--- a/src/tools/miri/tests/fail/no_main.stderr
+++ b/src/tools/miri/tests/fail/no_main.stderr
@@ -1,4 +1,11 @@
-error: miri can only run programs that have a main function
+error: Miri can only run programs that have a main function.
+       Alternatively, you can export a `miri_start` function:
+       
+       #[cfg(miri)]
+       #[no_mangle]
+       fn miri_start(argc: isize, argv: *const *const u8) -> isize {
+           // Call the actual start function that your project implements, based on your target's conventions.
+       }
 
 error: aborting due to 1 previous error
 
diff --git a/src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr b/src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr
index 50bff22f766..1ca35be8cb2 100644
--- a/src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr
+++ b/src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: memory access failed: $HEX[noalloc] is a dangling pointer (it has no provenance)
+error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
   --> $DIR/pointer_partial_overwrite.rs:LL:CC
    |
 LL |     let x = *p;
-   |             ^^ memory access failed: $HEX[noalloc] is a dangling pointer (it has no provenance)
+   |             ^^ memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr b/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr
index 6b1c2941c07..8a1d39effbd 100644
--- a/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr
+++ b/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: memory access failed: $HEX[noalloc] is a dangling pointer (it has no provenance)
+error: Undefined Behavior: memory access failed: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
   --> $DIR/provenance_transmute.rs:LL:CC
    |
 LL |         let _val = *left_ptr;
-   |                    ^^^^^^^^^ memory access failed: $HEX[noalloc] is a dangling pointer (it has no provenance)
+   |                    ^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.stderr b/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.stderr
index 92ccec50274..e21872244f6 100644
--- a/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.stderr
+++ b/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: memory access failed: $HEX[noalloc] is a dangling pointer (it has no provenance)
+error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
   --> $DIR/ptr_int_unexposed.rs:LL:CC
    |
 LL |     assert_eq!(unsafe { *ptr }, 3);
-   |                         ^^^^ memory access failed: $HEX[noalloc] is a dangling pointer (it has no provenance)
+   |                         ^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/provenance/ptr_invalid.stderr b/src/tools/miri/tests/fail/provenance/ptr_invalid.stderr
index 8b8033b0d1d..bd0a9eb0d29 100644
--- a/src/tools/miri/tests/fail/provenance/ptr_invalid.stderr
+++ b/src/tools/miri/tests/fail/provenance/ptr_invalid.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: memory access failed: $HEX[noalloc] is a dangling pointer (it has no provenance)
+error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
   --> $DIR/ptr_invalid.rs:LL:CC
    |
 LL |     let _val = unsafe { *xptr_invalid };
-   |                         ^^^^^^^^^^^^^ memory access failed: $HEX[noalloc] is a dangling pointer (it has no provenance)
+   |                         ^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/provenance/ptr_invalid_offset.stderr b/src/tools/miri/tests/fail/provenance/ptr_invalid_offset.stderr
index 8ae140ee004..35e5c08300f 100644
--- a/src/tools/miri/tests/fail/provenance/ptr_invalid_offset.stderr
+++ b/src/tools/miri/tests/fail/provenance/ptr_invalid_offset.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer arithmetic: $HEX[noalloc] is a dangling pointer (it has no provenance)
+error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
   --> $DIR/ptr_invalid_offset.rs:LL:CC
    |
 LL |     let _ = unsafe { roundtrip.offset(1) };
-   |                      ^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: $HEX[noalloc] is a dangling pointer (it has no provenance)
+   |                      ^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/reading_half_a_pointer.stderr b/src/tools/miri/tests/fail/reading_half_a_pointer.stderr
index 03f93510d09..cba8a9f8439 100644
--- a/src/tools/miri/tests/fail/reading_half_a_pointer.stderr
+++ b/src/tools/miri/tests/fail/reading_half_a_pointer.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: memory access failed: $HEX[noalloc] is a dangling pointer (it has no provenance)
+error: Undefined Behavior: memory access failed: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
   --> $DIR/reading_half_a_pointer.rs:LL:CC
    |
 LL |         let _val = *x;
-   |                    ^^ memory access failed: $HEX[noalloc] is a dangling pointer (it has no provenance)
+   |                    ^^ memory access failed: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.rs b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.rs
index 843d0d11873..75f7aae9718 100644
--- a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.rs
+++ b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.rs
@@ -4,6 +4,6 @@ extern "Rust" {
 
 fn main() {
     unsafe {
-        miri_resolve_frame(std::ptr::null_mut(), 0); //~ ERROR: null pointer is a dangling pointer
+        miri_resolve_frame(std::ptr::null_mut(), 0); //~ ERROR: got a null pointer
     }
 }
diff --git a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr
index 04dbd657d20..523c935762f 100644
--- a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr
+++ b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
+error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer
   --> $DIR/bad-backtrace-ptr.rs:LL:CC
    |
 LL |         miri_resolve_frame(std::ptr::null_mut(), 0);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr b/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr
index 7d000ba55e6..ce9a5b7f158 100644
--- a/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr
+++ b/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr
@@ -5,7 +5,7 @@ Warning: this tree is indicative only. Some tags may have been hidden.
 | RsM |      └─┬──<TAG=base>
 | RsM |        ├─┬──<TAG=x>
 | RsM |        │ └─┬──<TAG=caller:x>
-| RsM |        │   └────<TAG=callee:x> Strongly protected
+| Rs  |        │   └────<TAG=callee:x> Strongly protected
 | RsM |        └────<TAG=y, callee:y, caller:y>
 ──────────────────────────────────────────────────
 error: Undefined Behavior: write access through <TAG> (y, callee:y, caller:y) at ALLOC[0x0] is forbidden
@@ -16,14 +16,14 @@ LL |             *y = 1;
    |
    = 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> (y, callee:y, caller:y) is foreign to the protected tag <TAG> (callee:x) (i.e., it is not a child)
-   = help: this foreign write access would cause the protected tag <TAG> (callee:x) (currently Reserved (interior mutable)) to become Disabled
+   = help: this foreign write access would cause the protected tag <TAG> (callee:x) (currently Reserved) to become Disabled
    = help: protected tags must never be Disabled
 help: the accessed tag <TAG> was created here
   --> $DIR/cell-protected-write.rs:LL:CC
    |
 LL |         let y = (&mut *n).get();
    |                 ^^^^^^^^^
-help: the protected tag <TAG> was created here, in the initial state Reserved (interior mutable)
+help: the protected tag <TAG> was created here, in the initial state Reserved
   --> $DIR/cell-protected-write.rs:LL:CC
    |
 LL |         unsafe fn write_second(x: &mut UnsafeCell<u8>, y: *mut u8) {
diff --git a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs
new file mode 100644
index 00000000000..73f227fee2f
--- /dev/null
+++ b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs
@@ -0,0 +1,107 @@
+// Illustrating a problematic interaction between Reserved, interior mutability,
+// and protectors, that makes spurious writes fail in the previous model of Tree Borrows.
+// As for all similar tests, we disable preemption so that the error message is deterministic.
+//@compile-flags: -Zmiri-tree-borrows -Zmiri-preemption-rate=0
+//
+// One revision without spurious read (default source code) and one with spurious read.
+// Both are expected to be UB. Both revisions are expected to have the *same* error
+// because we are aligning the behavior of `without` to that of `with` so that the
+// spurious write is effectively a noop in the long term.
+//@revisions: without with
+
+use std::cell::Cell;
+use std::sync::{Arc, Barrier};
+use std::thread;
+
+// Here is the problematic interleaving:
+// - thread 1: retag and activate `x` (protected)
+// - thread 2: retag but do not initialize (lazy) `y` as Reserved with interior mutability
+// - thread 1: spurious write through `x` would go here
+// - thread 2: function exit (noop due to lazyness)
+// - thread 1: function exit (no permanent effect on `y` because it is now Reserved IM unprotected)
+// - thread 2: write through `y`
+// In the source code nothing happens to `y`
+
+// `Send`able raw pointer wrapper.
+#[derive(Copy, Clone)]
+struct SendPtr(*mut u8);
+unsafe impl Send for SendPtr {}
+
+type IdxBarrier = (usize, Arc<Barrier>);
+
+// Barriers to enforce the interleaving.
+// This macro expects `synchronized!(thread, msg)` where `thread` is a `IdxBarrier`,
+// and `msg` is the message to be displayed when the thread reaches this point in the execution.
+macro_rules! synchronized {
+    ($thread:expr, $msg:expr) => {{
+        let (thread_id, barrier) = &$thread;
+        eprintln!("Thread {} executing: {}", thread_id, $msg);
+        barrier.wait();
+    }};
+}
+
+fn main() {
+    // The conflict occurs on one single location but the example involves
+    // lazily initialized permissions. We will use `&mut Cell<()>` references
+    // to `data` to achieve this.
+    let mut data = 0u8;
+    let ptr = SendPtr(std::ptr::addr_of_mut!(data));
+    let barrier = Arc::new(Barrier::new(2));
+    let bx = Arc::clone(&barrier);
+    let by = Arc::clone(&barrier);
+
+    // Retag and activate `x`, wait until the other thread creates a lazy permission.
+    // Then do a spurious write. Finally exit the function after the other thread.
+    let thread_1 = thread::spawn(move || {
+        let b = (1, bx);
+        synchronized!(b, "start");
+        let ptr = ptr;
+        synchronized!(b, "retag x (&mut, protect)");
+        fn inner(x: &mut u8, b: IdxBarrier) {
+            *x = 42; // activate immediately
+            synchronized!(b, "[lazy] retag y (&mut, protect, IM)");
+            // A spurious write should be valid here because `x` is
+            // `Active` and protected.
+            if cfg!(with) {
+                synchronized!(b, "spurious write x (executed)");
+                *x = 64;
+            } else {
+                synchronized!(b, "spurious write x (skipped)");
+            }
+            synchronized!(b, "ret y");
+            synchronized!(b, "ret x");
+        }
+        inner(unsafe { &mut *ptr.0 }, b.clone());
+        synchronized!(b, "write y");
+        synchronized!(b, "end");
+    });
+
+    // Create a lazy Reserved with interior mutability.
+    // Wait for the other thread's spurious write then observe the side effects
+    // of that write.
+    let thread_2 = thread::spawn(move || {
+        let b = (2, by);
+        synchronized!(b, "start");
+        let ptr = ptr;
+        synchronized!(b, "retag x (&mut, protect)");
+        synchronized!(b, "[lazy] retag y (&mut, protect, IM)");
+        fn inner(y: &mut Cell<()>, b: IdxBarrier) -> *mut u8 {
+            synchronized!(b, "spurious write x");
+            synchronized!(b, "ret y");
+            // `y` is not retagged for any bytes, so the pointer we return
+            // has its permission lazily initialized.
+            y as *mut Cell<()> as *mut u8
+        }
+        // Currently `ptr` points to `data`.
+        // We do a zero-sized retag so that its permission is lazy.
+        let y_zst = unsafe { &mut *(ptr.0 as *mut Cell<()>) };
+        let y = inner(y_zst, b.clone());
+        synchronized!(b, "ret x");
+        synchronized!(b, "write y");
+        unsafe { *y = 13 } //~ERROR: /write access through .* is forbidden/
+        synchronized!(b, "end");
+    });
+
+    thread_1.join().unwrap();
+    thread_2.join().unwrap();
+}
diff --git a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr
new file mode 100644
index 00000000000..0e4517e9010
--- /dev/null
+++ b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr
@@ -0,0 +1,40 @@
+Thread 1 executing: start
+Thread 2 executing: start
+Thread 2 executing: retag x (&mut, protect)
+Thread 1 executing: retag x (&mut, protect)
+Thread 1 executing: [lazy] retag y (&mut, protect, IM)
+Thread 2 executing: [lazy] retag y (&mut, protect, IM)
+Thread 2 executing: spurious write x
+Thread 1 executing: spurious write x (executed)
+Thread 1 executing: ret y
+Thread 2 executing: ret y
+Thread 2 executing: ret x
+Thread 1 executing: ret x
+Thread 1 executing: write y
+Thread 2 executing: write y
+error: Undefined Behavior: write access through <TAG> at ALLOC[0x0] is forbidden
+  --> $DIR/reservedim_spurious_write.rs:LL:CC
+   |
+LL |         unsafe { *y = 13 }
+   |                  ^^^^^^^ write access through <TAG> at ALLOC[0x0] is forbidden
+   |
+   = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
+   = help: the accessed tag <TAG> has state Disabled which forbids this child write access
+help: the accessed tag <TAG> was created here, in the initial state Reserved
+  --> $DIR/reservedim_spurious_write.rs:LL:CC
+   |
+LL |         fn inner(y: &mut Cell<()>, b: IdxBarrier) -> *mut u8 {
+   |                  ^
+help: the accessed tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x0..0x1]
+  --> $DIR/reservedim_spurious_write.rs:LL:CC
+   |
+LL |                 *x = 64;
+   |                 ^^^^^^^
+   = help: this transition corresponds to a loss of read and write permissions
+   = note: BACKTRACE (of the first span) on thread `unnamed-ID`:
+   = note: inside closure at $DIR/reservedim_spurious_write.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.without.stderr b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.without.stderr
new file mode 100644
index 00000000000..cbeef90243b
--- /dev/null
+++ b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.without.stderr
@@ -0,0 +1,40 @@
+Thread 1 executing: start
+Thread 2 executing: start
+Thread 2 executing: retag x (&mut, protect)
+Thread 1 executing: retag x (&mut, protect)
+Thread 1 executing: [lazy] retag y (&mut, protect, IM)
+Thread 2 executing: [lazy] retag y (&mut, protect, IM)
+Thread 2 executing: spurious write x
+Thread 1 executing: spurious write x (skipped)
+Thread 1 executing: ret y
+Thread 2 executing: ret y
+Thread 2 executing: ret x
+Thread 1 executing: ret x
+Thread 1 executing: write y
+Thread 2 executing: write y
+error: Undefined Behavior: write access through <TAG> at ALLOC[0x0] is forbidden
+  --> $DIR/reservedim_spurious_write.rs:LL:CC
+   |
+LL |         unsafe { *y = 13 }
+   |                  ^^^^^^^ write access through <TAG> at ALLOC[0x0] is forbidden
+   |
+   = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
+   = help: the accessed tag <TAG> has state Disabled which forbids this child write access
+help: the accessed tag <TAG> was created here, in the initial state Reserved
+  --> $DIR/reservedim_spurious_write.rs:LL:CC
+   |
+LL |         fn inner(y: &mut Cell<()>, b: IdxBarrier) -> *mut u8 {
+   |                  ^
+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/reservedim_spurious_write.rs:LL:CC
+   |
+LL |         }
+   |          ^
+   = help: this transition corresponds to a loss of read and write permissions
+   = note: BACKTRACE (of the first span) on thread `unnamed-ID`:
+   = note: inside closure at $DIR/reservedim_spurious_write.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/validity/recursive-validity-ref-bool.rs b/src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.rs
new file mode 100644
index 00000000000..17b81f29cfe
--- /dev/null
+++ b/src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.rs
@@ -0,0 +1,8 @@
+//@compile-flags: -Zmiri-recursive-validation
+
+fn main() {
+    let x = 3u8;
+    let xref = &x;
+    let xref_wrong_type: &bool = unsafe { std::mem::transmute(xref) }; //~ERROR: encountered 0x03, but expected a boolean
+    let _val = *xref_wrong_type;
+}
diff --git a/src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.stderr b/src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.stderr
new file mode 100644
index 00000000000..2b2fa9b8a20
--- /dev/null
+++ b/src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: constructing invalid value at .<deref>: encountered 0x03, but expected a boolean
+  --> $DIR/recursive-validity-ref-bool.rs:LL:CC
+   |
+LL |     let xref_wrong_type: &bool = unsafe { std::mem::transmute(xref) };
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered 0x03, but expected a boolean
+   |
+   = 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/recursive-validity-ref-bool.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/zst_local_oob.rs b/src/tools/miri/tests/fail/zst_local_oob.rs
index cc81481e4fa..ab48b7d330b 100644
--- a/src/tools/miri/tests/fail/zst_local_oob.rs
+++ b/src/tools/miri/tests/fail/zst_local_oob.rs
@@ -1,5 +1,5 @@
 fn main() {
     // make sure ZST locals cannot be accessed
     let x = &() as *const () as *const i8;
-    let _val = unsafe { *x }; //~ ERROR: out-of-bounds
+    let _val = unsafe { *x }; //~ ERROR: expected a pointer to 1 byte of memory
 }
diff --git a/src/tools/miri/tests/fail/zst_local_oob.stderr b/src/tools/miri/tests/fail/zst_local_oob.stderr
index ba1ccaa0a3c..39ac2c91437 100644
--- a/src/tools/miri/tests/fail/zst_local_oob.stderr
+++ b/src/tools/miri/tests/fail/zst_local_oob.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: memory access failed: ALLOC has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds
+error: Undefined Behavior: memory access failed: expected a pointer to 1 byte of memory, but got ALLOC which is at or beyond the end of the allocation of size 0 bytes
   --> $DIR/zst_local_oob.rs:LL:CC
    |
 LL |     let _val = unsafe { *x };
-   |                         ^^ memory access failed: ALLOC has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds
+   |                         ^^ memory access failed: expected a pointer to 1 byte of memory, but got ALLOC which is at or beyond the end of the allocation of size 0 bytes
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/pass-dep/libc/gettid.rs b/src/tools/miri/tests/pass-dep/libc/gettid.rs
new file mode 100644
index 00000000000..87405b02ac3
--- /dev/null
+++ b/src/tools/miri/tests/pass-dep/libc/gettid.rs
@@ -0,0 +1,22 @@
+//@only-target-linux
+//@revisions: with_isolation without_isolation
+//@[without_isolation] compile-flags: -Zmiri-disable-isolation
+
+use libc::{getpid, gettid};
+use std::thread;
+
+fn main() {
+    thread::spawn(|| {
+        // Test that in isolation mode a deterministic value will be returned.
+        // The value 1001 is not important, we only care that whatever the value
+        // is, won't change from execution to execution.
+        #[cfg(with_isolation)]
+        assert_eq!(unsafe { gettid() }, 1001);
+
+        assert_ne!(unsafe { gettid() }, unsafe { getpid() });
+    });
+
+    // Test that the thread ID of the main thread is the same as the process
+    // ID.
+    assert_eq!(unsafe { gettid() }, unsafe { getpid() });
+}
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs-flock.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs-flock.rs
new file mode 100644
index 00000000000..3f7f9b18be9
--- /dev/null
+++ b/src/tools/miri/tests/pass-dep/libc/libc-fs-flock.rs
@@ -0,0 +1,70 @@
+//@ignore-target-windows: File handling is not implemented yet
+//@compile-flags: -Zmiri-disable-isolation
+
+use std::{fs::File, io::Error, os::fd::AsRawFd};
+
+#[path = "../../utils/mod.rs"]
+mod utils;
+
+fn main() {
+    let bytes = b"Hello, World!\n";
+    let path = utils::prepare_with_content("miri_test_fs_shared_lock.txt", bytes);
+
+    let files: Vec<File> = (0..3).map(|_| File::open(&path).unwrap()).collect();
+
+    // Test that we can apply many shared locks
+    for file in files.iter() {
+        let fd = file.as_raw_fd();
+        let ret = unsafe { libc::flock(fd, libc::LOCK_SH) };
+        if ret != 0 {
+            panic!("flock error: {}", Error::last_os_error());
+        }
+    }
+
+    // Test that shared lock prevents exclusive lock
+    {
+        let fd = files[0].as_raw_fd();
+        let ret = unsafe { libc::flock(fd, libc::LOCK_EX | libc::LOCK_NB) };
+        assert_eq!(ret, -1);
+        let err = Error::last_os_error().raw_os_error().unwrap();
+        assert_eq!(err, libc::EWOULDBLOCK);
+    }
+
+    // Unlock shared lock
+    for file in files.iter() {
+        let fd = file.as_raw_fd();
+        let ret = unsafe { libc::flock(fd, libc::LOCK_UN) };
+        if ret != 0 {
+            panic!("flock error: {}", Error::last_os_error());
+        }
+    }
+
+    // Take exclusive lock
+    {
+        let fd = files[0].as_raw_fd();
+        let ret = unsafe { libc::flock(fd, libc::LOCK_EX) };
+        assert_eq!(ret, 0);
+    }
+
+    // Test that shared lock prevents exclusive and shared locks
+    {
+        let fd = files[1].as_raw_fd();
+        let ret = unsafe { libc::flock(fd, libc::LOCK_EX | libc::LOCK_NB) };
+        assert_eq!(ret, -1);
+        let err = Error::last_os_error().raw_os_error().unwrap();
+        assert_eq!(err, libc::EWOULDBLOCK);
+
+        let fd = files[2].as_raw_fd();
+        let ret = unsafe { libc::flock(fd, libc::LOCK_SH | libc::LOCK_NB) };
+        assert_eq!(ret, -1);
+        let err = Error::last_os_error().raw_os_error().unwrap();
+        assert_eq!(err, libc::EWOULDBLOCK);
+    }
+
+    // Unlock exclusive lock
+    {
+        let fd = files[0].as_raw_fd();
+        let ret = unsafe { libc::flock(fd, libc::LOCK_UN) };
+        assert_eq!(ret, 0);
+    }
+}
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs-readlink.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs-symlink.rs
index d72edd7d9e3..619c6db3a29 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-fs-readlink.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-fs-symlink.rs
@@ -11,6 +11,11 @@ use std::os::unix::ffi::OsStrExt;
 mod utils;
 
 fn main() {
+    test_readlink();
+    test_nofollow_symlink();
+}
+
+fn test_readlink() {
     let bytes = b"Hello, World!\n";
     let path = utils::prepare_with_content("miri_test_fs_link_target.txt", bytes);
     let expected_path = path.as_os_str().as_bytes();
@@ -49,3 +54,18 @@ fn main() {
     assert_eq!(res, -1);
     assert_eq!(Error::last_os_error().kind(), ErrorKind::NotFound);
 }
+
+fn test_nofollow_symlink() {
+    let bytes = b"Hello, World!\n";
+    let path = utils::prepare_with_content("test_nofollow_symlink_target.txt", bytes);
+
+    let symlink_path = utils::prepare("test_nofollow_symlink.txt");
+    std::os::unix::fs::symlink(&path, &symlink_path).unwrap();
+
+    let symlink_cpath = CString::new(symlink_path.as_os_str().as_bytes()).unwrap();
+
+    let ret = unsafe { libc::open(symlink_cpath.as_ptr(), libc::O_NOFOLLOW | libc::O_CLOEXEC) };
+    assert_eq!(ret, -1);
+    let err = Error::last_os_error().raw_os_error().unwrap();
+    assert_eq!(err, libc::ELOOP);
+}
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 eddea92353e..5b2bbfbb27d 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs
@@ -37,6 +37,7 @@ fn main() {
     test_sync_file_range();
     test_isatty();
     test_read_and_uninit();
+    test_nofollow_not_symlink();
 }
 
 fn test_file_open_unix_allow_two_args() {
@@ -423,3 +424,11 @@ fn test_read_and_uninit() {
         remove_file(&path).unwrap();
     }
 }
+
+fn test_nofollow_not_symlink() {
+    let bytes = b"Hello, World!\n";
+    let path = utils::prepare_with_content("test_nofollow_not_symlink.txt", bytes);
+    let cpath = CString::new(path.as_os_str().as_bytes()).unwrap();
+    let ret = unsafe { libc::open(cpath.as_ptr(), libc::O_NOFOLLOW | libc::O_CLOEXEC) };
+    assert!(ret >= 0);
+}
diff --git a/src/tools/miri/tests/pass/adjacent-allocs.rs b/src/tools/miri/tests/pass/adjacent-allocs.rs
index 8be4bdac7e1..711c54fd68a 100644
--- a/src/tools/miri/tests/pass/adjacent-allocs.rs
+++ b/src/tools/miri/tests/pass/adjacent-allocs.rs
@@ -1,5 +1,3 @@
-//@revisions: stack tree
-//@[tree]compile-flags: -Zmiri-tree-borrows
 //@compile-flags: -Zmiri-permissive-provenance
 
 fn ensure_allocs_can_be_adjacent() {
diff --git a/src/tools/miri/tests/pass/alloc-access-tracking.rs b/src/tools/miri/tests/pass/alloc-access-tracking.rs
index a226783155b..40b8e23a33c 100644
--- a/src/tools/miri/tests/pass/alloc-access-tracking.rs
+++ b/src/tools/miri/tests/pass/alloc-access-tracking.rs
@@ -1,7 +1,7 @@
 #![feature(start)]
 #![no_std]
-//@compile-flags: -Zmiri-track-alloc-id=20 -Zmiri-track-alloc-accesses -Cpanic=abort
-//@normalize-stderr-test: "id 20" -> "id $$ALLOC"
+//@compile-flags: -Zmiri-track-alloc-id=21 -Zmiri-track-alloc-accesses -Cpanic=abort
+//@normalize-stderr-test: "id 21" -> "id $$ALLOC"
 //@only-target-linux: alloc IDs differ between OSes (due to extern static allocations)
 
 extern "Rust" {
diff --git a/src/tools/miri/tests/pass/async-fn.rs b/src/tools/miri/tests/pass/async-fn.rs
index 13400c88c71..67ec2e26b30 100644
--- a/src/tools/miri/tests/pass/async-fn.rs
+++ b/src/tools/miri/tests/pass/async-fn.rs
@@ -59,6 +59,7 @@ async fn hello_world() {
 }
 
 // This example comes from https://github.com/rust-lang/rust/issues/115145
+#[allow(unreachable_patterns)]
 async fn uninhabited_variant() {
     async fn unreachable(_: Never) {}
 
diff --git a/src/tools/miri/tests/pass/box.rs b/src/tools/miri/tests/pass/box.rs
index 174bf8be30b..693209c0456 100644
--- a/src/tools/miri/tests/pass/box.rs
+++ b/src/tools/miri/tests/pass/box.rs
@@ -1,5 +1,4 @@
-//@revisions: stack tree
-//@[tree]compile-flags: -Zmiri-tree-borrows -Zmiri-permissive-provenance
+//@compile-flags: -Zmiri-permissive-provenance
 #![feature(ptr_internals)]
 
 fn main() {
diff --git a/src/tools/miri/tests/pass/box.stack.stderr b/src/tools/miri/tests/pass/box.stack.stderr
deleted file mode 100644
index 341f84c8992..00000000000
--- a/src/tools/miri/tests/pass/box.stack.stderr
+++ /dev/null
@@ -1,33 +0,0 @@
-warning: integer-to-pointer cast
-  --> $DIR/box.rs:LL:CC
-   |
-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`, 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 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`
-  --> $DIR/box.rs:LL:CC
-   |
-LL |     into_raw();
-   |     ^^^^^^^^^^
-
-warning: integer-to-pointer cast
-  --> $DIR/box.rs:LL:CC
-   |
-LL |         let r = ((u.as_ptr() as usize) + 0) as *mut i32;
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast
-   |
-   = note: BACKTRACE:
-   = note: inside `into_unique` at $DIR/box.rs:LL:CC
-note: inside `main`
-  --> $DIR/box.rs:LL:CC
-   |
-LL |     into_unique();
-   |     ^^^^^^^^^^^^^
-
diff --git a/src/tools/miri/tests/pass/box.stack.stdout b/src/tools/miri/tests/pass/box.stdout
index 230ef368da6..230ef368da6 100644
--- a/src/tools/miri/tests/pass/box.stack.stdout
+++ b/src/tools/miri/tests/pass/box.stdout
diff --git a/src/tools/miri/tests/pass/box.tree.stdout b/src/tools/miri/tests/pass/box.tree.stdout
deleted file mode 100644
index 230ef368da6..00000000000
--- a/src/tools/miri/tests/pass/box.tree.stdout
+++ /dev/null
@@ -1,3 +0,0 @@
-pair_foo = PairFoo { fst: Foo(42), snd: Foo(1337) }
-foo #0 = Foo(42)
-foo #1 = Foo(1337)
diff --git a/src/tools/miri/tests/pass/dyn-traits.rs b/src/tools/miri/tests/pass/dyn-traits.rs
index 908d521a0d8..f6220120968 100644
--- a/src/tools/miri/tests/pass/dyn-traits.rs
+++ b/src/tools/miri/tests/pass/dyn-traits.rs
@@ -141,7 +141,17 @@ fn unsized_dyn_autoderef() {
 }
 */
 
+fn vtable_ptr_eq() {
+    use std::{fmt, ptr};
+
+    // We don't always get the same vtable when casting this to a wide pointer.
+    let x = &2;
+    let x_wide = x as &dyn fmt::Display;
+    assert!((0..256).any(|_| !ptr::eq(x as &dyn fmt::Display, x_wide)));
+}
+
 fn main() {
     ref_box_dyn();
     box_box_trait();
+    vtable_ptr_eq();
 }
diff --git a/src/tools/miri/tests/pass/enums.rs b/src/tools/miri/tests/pass/enums.rs
index ac7aafc1bb2..1dafef025e9 100644
--- a/src/tools/miri/tests/pass/enums.rs
+++ b/src/tools/miri/tests/pass/enums.rs
@@ -43,6 +43,7 @@ fn discriminant_overflow() {
     }
 }
 
+#[allow(unreachable_patterns)]
 fn more_discriminant_overflow() {
     pub enum Infallible {}
 
diff --git a/src/tools/miri/tests/pass/extern_types.rs b/src/tools/miri/tests/pass/extern_types.rs
index 7ac93577f0c..eade5c6ac08 100644
--- a/src/tools/miri/tests/pass/extern_types.rs
+++ b/src/tools/miri/tests/pass/extern_types.rs
@@ -1,12 +1,14 @@
 //@revisions: stack tree
-//@[tree]compile-flags: -Zmiri-tree-borrows -Zmiri-permissive-provenance
-#![feature(extern_types)]
+//@[tree]compile-flags: -Zmiri-tree-borrows
+#![feature(extern_types, strict_provenance)]
+
+use std::ptr;
 
 extern "C" {
     type Foo;
 }
 
 fn main() {
-    let x: &Foo = unsafe { &*(16 as *const Foo) };
+    let x: &Foo = unsafe { &*(ptr::without_provenance::<()>(16) as *const Foo) };
     let _y: &Foo = &*x;
 }
diff --git a/src/tools/miri/tests/pass/extern_types.stack.stderr b/src/tools/miri/tests/pass/extern_types.stack.stderr
index 03a9167abbc..2c9fc0192af 100644
--- a/src/tools/miri/tests/pass/extern_types.stack.stderr
+++ b/src/tools/miri/tests/pass/extern_types.stack.stderr
@@ -1,14 +1,11 @@
-warning: integer-to-pointer cast
+warning: reborrow of reference to `extern type`
   --> $DIR/extern_types.rs:LL:CC
    |
-LL |     let x: &Foo = unsafe { &*(16 as *const Foo) };
-   |                              ^^^^^^^^^^^^^^^^^^ integer-to-pointer cast
+LL |     let x: &Foo = unsafe { &*(ptr::without_provenance::<()>(16) as *const Foo) };
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reborrow of a reference to `extern type` is not properly supported
    |
-   = 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 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.
+   = help: `extern type` are not compatible with the Stacked Borrows aliasing model implemented by Miri; Miri may miss bugs in this code
+   = help: try running with `MIRIFLAGS=-Zmiri-tree-borrows` to use the more permissive but also even more experimental Tree Borrows aliasing checks instead
    = 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 2aa3ebf2dd0..a5c4bc5e0d9 100644
--- a/src/tools/miri/tests/pass/function_pointers.rs
+++ b/src/tools/miri/tests/pass/function_pointers.rs
@@ -82,7 +82,8 @@ fn main() {
     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.
-    assert!(return_fn_ptr(f) != f);
+    // at least if we try often enough.
+    assert!((0..256).any(|_| return_fn_ptr(f) != f));
     // However, if we only turn `f` into a function pointer and use that pointer,
     // it is equal to itself.
     let f2 = f as fn() -> i32;
diff --git a/src/tools/miri/tests/pass/getpid.rs b/src/tools/miri/tests/pass/getpid.rs
index 733545462eb..f350fafff4a 100644
--- a/src/tools/miri/tests/pass/getpid.rs
+++ b/src/tools/miri/tests/pass/getpid.rs
@@ -1,9 +1,20 @@
-//@compile-flags: -Zmiri-disable-isolation
+//@revisions: with_isolation without_isolation
+//@[without_isolation] compile-flags: -Zmiri-disable-isolation
 
 fn getpid() -> u32 {
     std::process::id()
 }
 
 fn main() {
-    getpid();
+    let pid = getpid();
+
+    std::thread::spawn(move || {
+        assert_eq!(getpid(), pid);
+    });
+
+    // Test that in isolation mode a deterministic value will be returned.
+    // The value 1000 is not important, we only care that whatever the value
+    // is, won't change from execution to execution.
+    #[cfg(with_isolation)]
+    assert_eq!(pid, 1000);
 }
diff --git a/src/tools/miri/tests/pass/intptrcast.rs b/src/tools/miri/tests/pass/intptrcast.rs
index fb1a1dfae5d..a304f2751bd 100644
--- a/src/tools/miri/tests/pass/intptrcast.rs
+++ b/src/tools/miri/tests/pass/intptrcast.rs
@@ -1,5 +1,3 @@
-//@revisions: stack tree
-//@[tree]compile-flags: -Zmiri-tree-borrows
 //@compile-flags: -Zmiri-permissive-provenance
 
 use std::mem;
diff --git a/src/tools/miri/tests/pass/miri_start.rs b/src/tools/miri/tests/pass/miri_start.rs
new file mode 100644
index 00000000000..756a1f60be1
--- /dev/null
+++ b/src/tools/miri/tests/pass/miri_start.rs
@@ -0,0 +1,19 @@
+//@compile-flags: -Cpanic=abort
+#![no_main]
+#![no_std]
+
+use core::fmt::Write;
+
+#[path = "../utils/mod.no_std.rs"]
+mod utils;
+
+#[no_mangle]
+fn miri_start(_argc: isize, _argv: *const *const u8) -> isize {
+    writeln!(utils::MiriStdout, "Hello from miri_start!").unwrap();
+    0
+}
+
+#[panic_handler]
+fn panic_handler(_: &core::panic::PanicInfo) -> ! {
+    loop {}
+}
diff --git a/src/tools/miri/tests/pass/miri_start.stdout b/src/tools/miri/tests/pass/miri_start.stdout
new file mode 100644
index 00000000000..1c9e8489b57
--- /dev/null
+++ b/src/tools/miri/tests/pass/miri_start.stdout
@@ -0,0 +1 @@
+Hello from miri_start!
diff --git a/src/tools/miri/tests/pass/pointers.rs b/src/tools/miri/tests/pass/pointers.rs
index c7b720dafa2..280a815abc4 100644
--- a/src/tools/miri/tests/pass/pointers.rs
+++ b/src/tools/miri/tests/pass/pointers.rs
@@ -1,5 +1,3 @@
-//@revisions: stack tree
-//@[tree]compile-flags: -Zmiri-tree-borrows
 //@compile-flags: -Zmiri-permissive-provenance
 #![feature(ptr_metadata, const_raw_ptr_comparison)]
 #![allow(ambiguous_wide_pointer_comparisons)]
diff --git a/src/tools/miri/tests/pass/ptr_int_casts.rs b/src/tools/miri/tests/pass/ptr_int_casts.rs
index a2fcd098107..684e8f6ec7b 100644
--- a/src/tools/miri/tests/pass/ptr_int_casts.rs
+++ b/src/tools/miri/tests/pass/ptr_int_casts.rs
@@ -1,6 +1,7 @@
 //@revisions: stack tree
+// Tree Borrows doesn't support int2ptr casts, but let's make sure we don't immediately crash either.
 //@[tree]compile-flags: -Zmiri-tree-borrows
-//@compile-flags: -Zmiri-permissive-provenance
+//@[stack]compile-flags: -Zmiri-permissive-provenance
 use std::mem;
 use std::ptr;
 
diff --git a/src/tools/miri/tests/pass/ptr_int_casts.tree.stderr b/src/tools/miri/tests/pass/ptr_int_casts.tree.stderr
new file mode 100644
index 00000000000..a34474ee0d6
--- /dev/null
+++ b/src/tools/miri/tests/pass/ptr_int_casts.tree.stderr
@@ -0,0 +1,89 @@
+warning: integer-to-pointer cast
+  --> $DIR/ptr_int_casts.rs:LL:CC
+   |
+LL |     assert_eq!(1 as *const i32 as usize, 1);
+   |                ^^^^^^^^^^^^^^^ integer-to-pointer cast
+   |
+   = 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 set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics
+   = help: Tree Borrows does not support integer-to-pointer casts, so the program is likely to go wrong when this pointer gets used
+   = note: BACKTRACE:
+   = note: inside `ptr_int_casts` at $DIR/ptr_int_casts.rs:LL:CC
+note: inside `main`
+  --> $DIR/ptr_int_casts.rs:LL:CC
+   |
+LL |     ptr_int_casts();
+   |     ^^^^^^^^^^^^^^^
+
+warning: integer-to-pointer cast
+  --> $DIR/ptr_int_casts.rs:LL:CC
+   |
+LL |     assert_eq!((1 as *const i32).wrapping_offset(4) as usize, 1 + 4 * 4);
+   |                ^^^^^^^^^^^^^^^^^ integer-to-pointer cast
+   |
+   = note: BACKTRACE:
+   = note: inside `ptr_int_casts` at $DIR/ptr_int_casts.rs:LL:CC
+note: inside `main`
+  --> $DIR/ptr_int_casts.rs:LL:CC
+   |
+LL |     ptr_int_casts();
+   |     ^^^^^^^^^^^^^^^
+
+warning: integer-to-pointer cast
+  --> $DIR/ptr_int_casts.rs:LL:CC
+   |
+LL |     *val = (1 as *const u8).wrapping_offset(-4);
+   |            ^^^^^^^^^^^^^^^^ integer-to-pointer cast
+   |
+   = note: BACKTRACE:
+   = note: inside `ptr_int_casts` at $DIR/ptr_int_casts.rs:LL:CC
+note: inside `main`
+  --> $DIR/ptr_int_casts.rs:LL:CC
+   |
+LL |     ptr_int_casts();
+   |     ^^^^^^^^^^^^^^^
+
+warning: integer-to-pointer cast
+  --> $DIR/ptr_int_casts.rs:LL:CC
+   |
+LL |         let y = y as *const _;
+   |                 ^^^^^^^^^^^^^ integer-to-pointer cast
+   |
+   = note: BACKTRACE:
+   = note: inside `ptr_int_casts` at $DIR/ptr_int_casts.rs:LL:CC
+note: inside `main`
+  --> $DIR/ptr_int_casts.rs:LL:CC
+   |
+LL |     ptr_int_casts();
+   |     ^^^^^^^^^^^^^^^
+
+warning: integer-to-pointer cast
+  --> $DIR/ptr_int_casts.rs:LL:CC
+   |
+LL |         let x: fn() -> i32 = unsafe { mem::transmute(y as *mut u8) };
+   |                                                      ^^^^^^^^^^^^ integer-to-pointer cast
+   |
+   = note: BACKTRACE:
+   = note: inside `ptr_int_casts` at $DIR/ptr_int_casts.rs:LL:CC
+note: inside `main`
+  --> $DIR/ptr_int_casts.rs:LL:CC
+   |
+LL |     ptr_int_casts();
+   |     ^^^^^^^^^^^^^^^
+
+warning: integer-to-pointer cast
+  --> $DIR/ptr_int_casts.rs:LL:CC
+   |
+LL |     assert_eq!((-1i32) as usize as *const i32 as usize, (-1i32) as usize);
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast
+   |
+   = note: BACKTRACE:
+   = note: inside `ptr_int_casts` at $DIR/ptr_int_casts.rs:LL:CC
+note: inside `main`
+  --> $DIR/ptr_int_casts.rs:LL:CC
+   |
+LL |     ptr_int_casts();
+   |     ^^^^^^^^^^^^^^^
+
diff --git a/src/tools/miri/tests/pass/ptr_int_from_exposed.rs b/src/tools/miri/tests/pass/ptr_int_from_exposed.rs
index 5690d7865bb..ade5f537785 100644
--- a/src/tools/miri/tests/pass/ptr_int_from_exposed.rs
+++ b/src/tools/miri/tests/pass/ptr_int_from_exposed.rs
@@ -1,6 +1,7 @@
 //@revisions: stack tree
+// Tree Borrows doesn't support int2ptr casts, but let's make sure we don't immediately crash either.
 //@[tree]compile-flags: -Zmiri-tree-borrows
-//@compile-flags: -Zmiri-permissive-provenance
+//@[stack]compile-flags: -Zmiri-permissive-provenance
 #![feature(strict_provenance, exposed_provenance)]
 
 use std::ptr;
@@ -56,9 +57,18 @@ fn ptr_roundtrip_null() {
     assert_eq!(unsafe { *x_ptr_copy }, 42);
 }
 
+fn ptr_roundtrip_offset_from() {
+    let arr = [0; 5];
+    let begin = arr.as_ptr();
+    let end = begin.wrapping_add(arr.len());
+    let end_roundtrip = ptr::with_exposed_provenance::<i32>(end.expose_provenance());
+    unsafe { end_roundtrip.offset_from(begin) };
+}
+
 fn main() {
     ptr_roundtrip_out_of_bounds();
     ptr_roundtrip_confusion();
     ptr_roundtrip_imperfect();
     ptr_roundtrip_null();
+    ptr_roundtrip_offset_from();
 }
diff --git a/src/tools/miri/tests/pass/ptr_int_from_exposed.tree.stderr b/src/tools/miri/tests/pass/ptr_int_from_exposed.tree.stderr
new file mode 100644
index 00000000000..614b0d26a63
--- /dev/null
+++ b/src/tools/miri/tests/pass/ptr_int_from_exposed.tree.stderr
@@ -0,0 +1,19 @@
+warning: integer-to-pointer cast
+  --> $DIR/ptr_int_from_exposed.rs:LL:CC
+   |
+LL |     let ptr = ptr::with_exposed_provenance::<i32>(x_usize).wrapping_offset(-128);
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast
+   |
+   = 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 set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics
+   = help: Tree Borrows does not support integer-to-pointer casts, so the program is likely to go wrong when this pointer gets used
+   = note: BACKTRACE:
+   = note: inside `ptr_roundtrip_out_of_bounds` at $DIR/ptr_int_from_exposed.rs:LL:CC
+note: inside `main`
+  --> $DIR/ptr_int_from_exposed.rs:LL:CC
+   |
+LL |     ptr_roundtrip_out_of_bounds();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/src/tools/miri/tests/pass/rc.rs b/src/tools/miri/tests/pass/rc.rs
index 6dd1b3aff9e..b1470dabc26 100644
--- a/src/tools/miri/tests/pass/rc.rs
+++ b/src/tools/miri/tests/pass/rc.rs
@@ -75,7 +75,8 @@ fn rc_fat_ptr_eq() {
     let p = Rc::new(1) as Rc<dyn Debug>;
     let a: *const dyn Debug = &*p;
     let r = Rc::into_raw(p);
-    assert!(a == r);
+    // Only compare the pointer parts, as the vtable might differ.
+    assert!(a as *const () == r as *const ());
     drop(unsafe { Rc::from_raw(r) });
 }
 
diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs
index 16d3e8cab30..70e375b0981 100644
--- a/src/tools/miri/tests/pass/shims/fs.rs
+++ b/src/tools/miri/tests/pass/shims/fs.rs
@@ -30,6 +30,8 @@ fn main() {
     test_directory();
     test_canonicalize();
     test_from_raw_os_error();
+    #[cfg(unix)]
+    test_pread_pwrite();
 }
 
 fn test_path_conversion() {
@@ -303,3 +305,42 @@ fn test_from_raw_os_error() {
     // Make sure we can also format this.
     let _ = format!("{error:?}");
 }
+
+#[cfg(unix)]
+fn test_pread_pwrite() {
+    use std::os::unix::fs::FileExt;
+
+    let bytes = b"hello world";
+    let path = utils::prepare_with_content("miri_test_fs_pread_pwrite.txt", bytes);
+    let mut f = OpenOptions::new().read(true).write(true).open(path).unwrap();
+
+    let mut buf1 = [0u8; 3];
+    f.seek(SeekFrom::Start(5)).unwrap();
+
+    // Check that we get expected result after seek
+    f.read_exact(&mut buf1).unwrap();
+    assert_eq!(&buf1, b" wo");
+    f.seek(SeekFrom::Start(5)).unwrap();
+
+    // Check pread
+    f.read_exact_at(&mut buf1, 2).unwrap();
+    assert_eq!(&buf1, b"llo");
+    f.read_exact_at(&mut buf1, 6).unwrap();
+    assert_eq!(&buf1, b"wor");
+
+    // Ensure that cursor position is not changed
+    f.read_exact(&mut buf1).unwrap();
+    assert_eq!(&buf1, b" wo");
+    f.seek(SeekFrom::Start(5)).unwrap();
+
+    // Check pwrite
+    f.write_all_at(b" mo", 6).unwrap();
+
+    let mut buf2 = [0u8; 11];
+    f.read_exact_at(&mut buf2, 0).unwrap();
+    assert_eq!(&buf2, b"hello  mold");
+
+    // Ensure that cursor position is not changed
+    f.read_exact(&mut buf1).unwrap();
+    assert_eq!(&buf1, b"  m");
+}
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 b0e1adf27d1..216bb6c76bc 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,11 +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`, 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 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.
+   = 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 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/tree_borrows/reserved.stderr b/src/tools/miri/tests/pass/tree_borrows/reserved.stderr
index 0d0d52c717f..d149a4065f9 100644
--- a/src/tools/miri/tests/pass/tree_borrows/reserved.stderr
+++ b/src/tools/miri/tests/pass/tree_borrows/reserved.stderr
@@ -6,7 +6,7 @@ Warning: this tree is indicative only. Some tags may have been hidden.
 | RsM |      └─┬──<TAG=base>
 | RsM |        ├─┬──<TAG=x>
 | RsM |        │ └─┬──<TAG=caller:x>
-| RsCM|        │   └────<TAG=callee:x>
+| RsC |        │   └────<TAG=callee:x>
 | RsM |        └────<TAG=y, caller:y, callee:y>
 ──────────────────────────────────────────────────
 [interior mut] Foreign Read: Re* -> Re*
diff --git a/src/tools/miri/tests/pass/tree_borrows/vec_unique.rs b/src/tools/miri/tests/pass/tree_borrows/vec_unique.rs
index 05090d685ab..9debe224d45 100644
--- a/src/tools/miri/tests/pass/tree_borrows/vec_unique.rs
+++ b/src/tools/miri/tests/pass/tree_borrows/vec_unique.rs
@@ -1,3 +1,5 @@
+// FIXME: This test is broken since https://github.com/rust-lang/rust/pull/126793,
+// possibly related to the additional struct between Vec and Unique.
 //@revisions: default uniq
 // We disable the GC for this test because it would change what is printed.
 //@compile-flags: -Zmiri-tree-borrows -Zmiri-provenance-gc=0
diff --git a/src/tools/miri/tests/pass/tree_borrows/vec_unique.uniq.stderr b/src/tools/miri/tests/pass/tree_borrows/vec_unique.uniq.stderr
index 7942e9884f4..e3796a742e9 100644
--- a/src/tools/miri/tests/pass/tree_borrows/vec_unique.uniq.stderr
+++ b/src/tools/miri/tests/pass/tree_borrows/vec_unique.uniq.stderr
@@ -2,7 +2,9 @@
 Warning: this tree is indicative only. Some tags may have been hidden.
 0..   2
 | Act |    └─┬──<TAG=root of the allocation>
-|-----|      └─┬──<TAG=base.as_ptr(), base.as_ptr()>
-|-----|        └─┬──<TAG=raw_parts.0>
-|-----|          └────<TAG=reconstructed.as_ptr(), reconstructed.as_ptr()>
+|-----|      ├────<TAG=base.as_ptr()>
+|-----|      ├────<TAG=base.as_ptr()>
+|-----|      └─┬──<TAG=raw_parts.0>
+|-----|        ├────<TAG=reconstructed.as_ptr()>
+|-----|        └────<TAG=reconstructed.as_ptr()>
 ──────────────────────────────────────────────────
diff --git a/src/tools/miri/tests/ui.rs b/src/tools/miri/tests/ui.rs
index 3a8b098ccbe..95f8b054102 100644
--- a/src/tools/miri/tests/ui.rs
+++ b/src/tools/miri/tests/ui.rs
@@ -73,7 +73,7 @@ fn miri_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) ->
         stdout_filters: stdout_filters().into(),
         mode,
         program,
-        out_dir: PathBuf::from(std::env::var_os("CARGO_TARGET_DIR").unwrap()).join("ui"),
+        out_dir: PathBuf::from(std::env::var_os("CARGO_TARGET_DIR").unwrap()).join("miri_ui"),
         edition: Some("2021".into()), // keep in sync with `./miri run`
         threads: std::env::var("MIRI_TEST_THREADS")
             .ok()
diff --git a/src/tools/opt-dist/Cargo.toml b/src/tools/opt-dist/Cargo.toml
index 88e8640d56a..d34f8ad0520 100644
--- a/src/tools/opt-dist/Cargo.toml
+++ b/src/tools/opt-dist/Cargo.toml
@@ -10,7 +10,7 @@ log = "0.4"
 anyhow = { version = "1", features = ["backtrace"] }
 humantime = "2"
 humansize = "2"
-sysinfo = { version = "0.30", default-features = false }
+sysinfo = { version = "0.31.2", default-features = false, features = ["disk"] }
 fs_extra = "1"
 camino = "1"
 tar = "0.4"
diff --git a/src/tools/opt-dist/src/bolt.rs b/src/tools/opt-dist/src/bolt.rs
index eb10426f060..d9efbb8d880 100644
--- a/src/tools/opt-dist/src/bolt.rs
+++ b/src/tools/opt-dist/src/bolt.rs
@@ -1,9 +1,8 @@
 use anyhow::Context;
+use camino::{Utf8Path, Utf8PathBuf};
 
 use crate::exec::cmd;
 use crate::training::BoltProfile;
-use camino::{Utf8Path, Utf8PathBuf};
-
 use crate::utils::io::copy_file;
 
 /// Instruments an artifact at the given `path` (in-place) with BOLT and then calls `func`.
diff --git a/src/tools/opt-dist/src/exec.rs b/src/tools/opt-dist/src/exec.rs
index 90a045e83d7..e50f2600e85 100644
--- a/src/tools/opt-dist/src/exec.rs
+++ b/src/tools/opt-dist/src/exec.rs
@@ -1,11 +1,13 @@
+use std::collections::BTreeMap;
+use std::fs::File;
+use std::process::{Command, Stdio};
+
+use camino::{Utf8Path, Utf8PathBuf};
+
 use crate::environment::Environment;
 use crate::metrics::{load_metrics, record_metrics};
 use crate::timer::TimerSection;
 use crate::training::{BoltProfile, LlvmPGOProfile, RustcPGOProfile};
-use camino::{Utf8Path, Utf8PathBuf};
-use std::collections::BTreeMap;
-use std::fs::File;
-use std::process::{Command, Stdio};
 
 #[derive(Default)]
 pub struct CmdBuilder {
diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs
index e4271a6e2dd..73389f930bd 100644
--- a/src/tools/opt-dist/src/main.rs
+++ b/src/tools/opt-dist/src/main.rs
@@ -1,10 +1,10 @@
-use crate::bolt::{bolt_optimize, with_bolt_instrumented};
 use anyhow::Context;
 use camino::{Utf8Path, Utf8PathBuf};
 use clap::Parser;
 use log::LevelFilter;
 use utils::io;
 
+use crate::bolt::{bolt_optimize, with_bolt_instrumented};
 use crate::environment::{Environment, EnvironmentBuilder};
 use crate::exec::{cmd, Bootstrap};
 use crate::tests::run_tests;
diff --git a/src/tools/opt-dist/src/metrics.rs b/src/tools/opt-dist/src/metrics.rs
index cabe07eda32..89c4cb12d4c 100644
--- a/src/tools/opt-dist/src/metrics.rs
+++ b/src/tools/opt-dist/src/metrics.rs
@@ -1,7 +1,9 @@
-use crate::timer::TimerSection;
+use std::time::Duration;
+
 use build_helper::metrics::{JsonNode, JsonRoot};
 use camino::Utf8Path;
-use std::time::Duration;
+
+use crate::timer::TimerSection;
 
 #[derive(Clone, Debug)]
 pub struct BuildStep {
diff --git a/src/tools/opt-dist/src/tests.rs b/src/tools/opt-dist/src/tests.rs
index d03d1936e08..30c9648bc08 100644
--- a/src/tools/opt-dist/src/tests.rs
+++ b/src/tools/opt-dist/src/tests.rs
@@ -1,8 +1,9 @@
+use anyhow::Context;
+use camino::{Utf8Path, Utf8PathBuf};
+
 use crate::environment::{executable_extension, Environment};
 use crate::exec::cmd;
 use crate::utils::io::{copy_directory, find_file_in_dir, unpack_archive};
-use anyhow::Context;
-use camino::{Utf8Path, Utf8PathBuf};
 
 /// Run tests on optimized dist artifacts.
 pub fn run_tests(env: &Environment) -> anyhow::Result<()> {
@@ -59,17 +60,26 @@ pub fn run_tests(env: &Environment) -> anyhow::Result<()> {
         .join(format!("llvm-config{}", executable_extension()));
     assert!(llvm_config.is_file());
 
-    let rustc = format!("build.rustc={}", rustc_path.to_string().replace('\\', "/"));
-    let cargo = format!("build.cargo={}", cargo_path.to_string().replace('\\', "/"));
-    let llvm_config =
-        format!("target.{host_triple}.llvm-config={}", llvm_config.to_string().replace('\\', "/"));
+    let config_content = format!(
+        r#"profile = "user"
+change-id = 115898
+
+[build]
+rustc = "{rustc}"
+cargo = "{cargo}"
 
-    log::info!("Set the following configurations for running tests:");
-    log::info!("\t{rustc}");
-    log::info!("\t{cargo}");
-    log::info!("\t{llvm_config}");
+[target.{host_triple}]
+llvm-config = "{llvm_config}"
+"#,
+        rustc = rustc_path.to_string().replace('\\', "/"),
+        cargo = cargo_path.to_string().replace('\\', "/"),
+        llvm_config = llvm_config.to_string().replace('\\', "/")
+    );
+    log::info!("Using following `config.toml` for running tests:\n{config_content}");
 
     // Simulate a stage 0 compiler with the extracted optimized dist artifacts.
+    std::fs::write("config.toml", config_content)?;
+
     let x_py = env.checkout_path().join("x.py");
     let mut args = vec![
         env.python_binary(),
@@ -88,12 +98,6 @@ pub fn run_tests(env: &Environment) -> anyhow::Result<()> {
         "tests/run-pass-valgrind",
         "tests/ui",
         "tests/crashes",
-        "--set",
-        &rustc,
-        "--set",
-        &cargo,
-        "--set",
-        &llvm_config,
     ];
     for test_path in env.skipped_tests() {
         args.extend(["--skip", test_path]);
diff --git a/src/tools/opt-dist/src/training.rs b/src/tools/opt-dist/src/training.rs
index 1237951b3f0..97e8ec5c6ed 100644
--- a/src/tools/opt-dist/src/training.rs
+++ b/src/tools/opt-dist/src/training.rs
@@ -1,12 +1,13 @@
-use crate::environment::{executable_extension, Environment};
-use crate::exec::{cmd, CmdBuilder};
-use crate::utils::io::{count_files, delete_directory};
-use crate::utils::with_log_group;
 use anyhow::Context;
 use build_helper::{LLVM_PGO_CRATES, RUSTC_PGO_CRATES};
 use camino::{Utf8Path, Utf8PathBuf};
 use humansize::BINARY;
 
+use crate::environment::{executable_extension, Environment};
+use crate::exec::{cmd, CmdBuilder};
+use crate::utils::io::{count_files, delete_directory};
+use crate::utils::with_log_group;
+
 fn init_compiler_benchmarks(
     env: &Environment,
     profiles: &[&str],
diff --git a/src/tools/opt-dist/src/utils/artifact_size.rs b/src/tools/opt-dist/src/utils/artifact_size.rs
index b6c453fb40b..e51b5f06dfb 100644
--- a/src/tools/opt-dist/src/utils/artifact_size.rs
+++ b/src/tools/opt-dist/src/utils/artifact_size.rs
@@ -9,10 +9,10 @@ use crate::environment::Environment;
 use crate::utils::io::get_files_from_dir;
 
 pub fn print_binary_sizes(env: &Environment) -> anyhow::Result<()> {
-    use humansize::format_size;
-    use humansize::BINARY;
     use std::fmt::Write;
 
+    use humansize::{format_size, BINARY};
+
     let root = env.build_artifacts().join("stage2");
 
     let mut files = get_files_from_dir(&root.join("bin"), None)?;
diff --git a/src/tools/opt-dist/src/utils/io.rs b/src/tools/opt-dist/src/utils/io.rs
index d6bd5cb85e4..ce425bdfece 100644
--- a/src/tools/opt-dist/src/utils/io.rs
+++ b/src/tools/opt-dist/src/utils/io.rs
@@ -1,8 +1,9 @@
+use std::fs::File;
+use std::path::Path;
+
 use anyhow::Context;
 use camino::{Utf8Path, Utf8PathBuf};
 use fs_extra::dir::CopyOptions;
-use std::fs::File;
-use std::path::Path;
 
 /// Delete and re-create the directory.
 pub fn reset_directory(path: &Utf8Path) -> anyhow::Result<()> {
diff --git a/src/tools/opt-dist/src/utils/mod.rs b/src/tools/opt-dist/src/utils/mod.rs
index 22b0483c071..32d88a59af9 100644
--- a/src/tools/opt-dist/src/utils/mod.rs
+++ b/src/tools/opt-dist/src/utils/mod.rs
@@ -1,10 +1,11 @@
+use std::time::Duration;
+
+use humansize::BINARY;
 use sysinfo::Disks;
 
 use crate::environment::Environment;
 use crate::timer::Timer;
 use crate::utils::io::delete_directory;
-use humansize::BINARY;
-use std::time::Duration;
 
 pub mod artifact_size;
 pub mod io;
diff --git a/src/tools/remote-test-client/src/main.rs b/src/tools/remote-test-client/src/main.rs
index 42de3caf547..bda08423487 100644
--- a/src/tools/remote-test-client/src/main.rs
+++ b/src/tools/remote-test-client/src/main.rs
@@ -5,15 +5,14 @@
 //! Here is also where we bake in the support to spawn the QEMU emulator as
 //! well.
 
-use std::env;
 use std::fs::{self, File};
 use std::io::prelude::*;
 use std::io::{self, BufWriter};
 use std::net::TcpStream;
 use std::path::{Path, PathBuf};
 use std::process::{Command, Stdio};
-use std::thread;
 use std::time::Duration;
+use std::{env, thread};
 
 const REMOTE_ADDR_ENV: &str = "TEST_DEVICE_ADDR";
 const DEFAULT_ADDR: &str = "127.0.0.1:12345";
diff --git a/src/tools/remote-test-server/src/main.rs b/src/tools/remote-test-server/src/main.rs
index 79f96c50223..67a7ad6f3b4 100644
--- a/src/tools/remote-test-server/src/main.rs
+++ b/src/tools/remote-test-server/src/main.rs
@@ -12,22 +12,17 @@
 
 #[cfg(not(windows))]
 use std::fs::Permissions;
-use std::net::SocketAddr;
-#[cfg(not(windows))]
-use std::os::unix::prelude::*;
-
-use std::cmp;
-use std::env;
 use std::fs::{self, File};
 use std::io::prelude::*;
 use std::io::{self, BufReader};
-use std::net::{TcpListener, TcpStream};
+use std::net::{SocketAddr, TcpListener, TcpStream};
+#[cfg(not(windows))]
+use std::os::unix::prelude::*;
 use std::path::{Path, PathBuf};
 use std::process::{Command, ExitStatus, Stdio};
-use std::str;
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::sync::{Arc, Mutex};
-use std::thread;
+use std::{cmp, env, str, thread};
 
 macro_rules! t {
     ($e:expr) => {
diff --git a/src/tools/replace-version-placeholder/src/main.rs b/src/tools/replace-version-placeholder/src/main.rs
index 5c9c18b9b36..247e4e7e932 100644
--- a/src/tools/replace-version-placeholder/src/main.rs
+++ b/src/tools/replace-version-placeholder/src/main.rs
@@ -1,4 +1,5 @@
 use std::path::PathBuf;
+
 use tidy::{t, walk};
 
 pub const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION";
diff --git a/src/tools/rls/src/main.rs b/src/tools/rls/src/main.rs
index d7be108e89c..3a95b47cd4d 100644
--- a/src/tools/rls/src/main.rs
+++ b/src/tools/rls/src/main.rs
@@ -3,10 +3,10 @@
 //! This is a small stub that replaces RLS to alert the user that RLS is no
 //! longer available.
 
-use serde_json::Value;
 use std::error::Error;
-use std::io::BufRead;
-use std::io::Write;
+use std::io::{BufRead, Write};
+
+use serde_json::Value;
 
 const ALERT_MSG: &str = "\
 RLS is no longer available as of Rust 1.65.
diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml
index b3913732839..c4d5446a248 100644
--- a/src/tools/run-make-support/Cargo.toml
+++ b/src/tools/run-make-support/Cargo.toml
@@ -5,9 +5,9 @@ edition = "2021"
 
 [dependencies]
 bstr = "1.6.0"
-object = "0.34.0"
+object = "0.36.2"
 similar = "2.5.0"
-wasmparser = "0.118.2"
+wasmparser = { version = "0.214", default-features = false, features = ["std"] }
 regex = "1.8" # 1.8 to avoid memchr 2.6.0, as 2.5.0 is pinned in the workspace
 gimli = "0.31.0"
 build_helper = { path = "../build_helper" }
diff --git a/src/tools/run-make-support/src/artifact_names.rs b/src/tools/run-make-support/src/artifact_names.rs
index bc6ec7566e5..0d7b5cb9838 100644
--- a/src/tools/run-make-support/src/artifact_names.rs
+++ b/src/tools/run-make-support/src/artifact_names.rs
@@ -38,6 +38,17 @@ pub fn dynamic_lib_name(name: &str) -> String {
     format!("{}{name}.{}", std::env::consts::DLL_PREFIX, std::env::consts::DLL_EXTENSION)
 }
 
+/// Construct the name of the import library for the dynamic library, exclusive to MSVC and
+/// accepted by link.exe.
+#[track_caller]
+#[must_use]
+pub fn msvc_import_dynamic_lib_name(name: &str) -> String {
+    assert!(is_msvc(), "this function is exclusive to MSVC");
+    assert!(!name.contains(char::is_whitespace), "import library name cannot contain whitespace");
+
+    format!("{name}.dll.lib")
+}
+
 /// Construct the dynamic library extension based on the target.
 #[must_use]
 pub fn dynamic_lib_extension() -> &'static str {
diff --git a/src/tools/run-make-support/src/assertion_helpers.rs b/src/tools/run-make-support/src/assertion_helpers.rs
index 4b5b349431d..6d256fc594d 100644
--- a/src/tools/run-make-support/src/assertion_helpers.rs
+++ b/src/tools/run-make-support/src/assertion_helpers.rs
@@ -3,7 +3,7 @@
 use std::panic;
 use std::path::Path;
 
-use crate::fs;
+use crate::{fs, regex};
 
 /// Assert that `actual` is equal to `expected`.
 #[track_caller]
@@ -47,6 +47,36 @@ pub fn assert_not_contains<H: AsRef<str>, N: AsRef<str>>(haystack: H, needle: N)
     }
 }
 
+/// Assert that `haystack` contains the regex pattern `needle`.
+#[track_caller]
+pub fn assert_contains_regex<H: AsRef<str>, N: AsRef<str>>(haystack: H, needle: N) {
+    let haystack = haystack.as_ref();
+    let needle = needle.as_ref();
+    let re = regex::Regex::new(needle).unwrap();
+    if !re.is_match(haystack) {
+        eprintln!("=== HAYSTACK ===");
+        eprintln!("{}", haystack);
+        eprintln!("=== NEEDLE ===");
+        eprintln!("{}", needle);
+        panic!("needle was not found in haystack");
+    }
+}
+
+/// Assert that `haystack` does not contain the regex pattern `needle`.
+#[track_caller]
+pub fn assert_not_contains_regex<H: AsRef<str>, N: AsRef<str>>(haystack: H, needle: N) {
+    let haystack = haystack.as_ref();
+    let needle = needle.as_ref();
+    let re = regex::Regex::new(needle).unwrap();
+    if re.is_match(haystack) {
+        eprintln!("=== HAYSTACK ===");
+        eprintln!("{}", haystack);
+        eprintln!("=== NEEDLE ===");
+        eprintln!("{}", needle);
+        panic!("needle was unexpectedly found in haystack");
+    }
+}
+
 /// Assert that all files in `dir1` exist and have the same content in `dir2`
 pub fn assert_dirs_are_equal(dir1: impl AsRef<Path>, dir2: impl AsRef<Path>) {
     let dir2 = dir2.as_ref();
diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs
index 47376c401bb..a0b96e25a0c 100644
--- a/src/tools/run-make-support/src/command.rs
+++ b/src/tools/run-make-support/src/command.rs
@@ -1,15 +1,17 @@
-use std::ffi;
 use std::ffi::OsStr;
 use std::io::Write;
-use std::panic;
 use std::path::Path;
 use std::process::{Command as StdCommand, ExitStatus, Output, Stdio};
-
-use crate::util::handle_failed_output;
-use crate::{assert_contains, assert_equals, assert_not_contains};
+use std::{ffi, panic};
 
 use build_helper::drop_bomb::DropBomb;
 
+use crate::util::handle_failed_output;
+use crate::{
+    assert_contains, assert_contains_regex, assert_equals, assert_not_contains,
+    assert_not_contains_regex,
+};
+
 /// This is a custom command wrapper that simplifies working with commands and makes it easier to
 /// ensure that we check the exit status of executed processes.
 ///
@@ -164,11 +166,19 @@ pub struct CompletedProcess {
 
 impl CompletedProcess {
     #[must_use]
+    #[track_caller]
     pub fn stdout_utf8(&self) -> String {
         String::from_utf8(self.output.stdout.clone()).expect("stdout is not valid UTF-8")
     }
 
     #[must_use]
+    #[track_caller]
+    pub fn invalid_stdout_utf8(&self) -> String {
+        String::from_utf8_lossy(&self.output.stdout.clone()).to_string()
+    }
+
+    #[must_use]
+    #[track_caller]
     pub fn stderr_utf8(&self) -> String {
         String::from_utf8(self.output.stderr.clone()).expect("stderr is not valid UTF-8")
     }
@@ -192,6 +202,13 @@ impl CompletedProcess {
         self
     }
 
+    /// Checks that `stdout` does not contain the regex pattern `unexpected`.
+    #[track_caller]
+    pub fn assert_stdout_not_contains_regex<S: AsRef<str>>(&self, unexpected: S) -> &Self {
+        assert_not_contains_regex(&self.stdout_utf8(), unexpected);
+        self
+    }
+
     /// Checks that `stdout` contains `expected`.
     #[track_caller]
     pub fn assert_stdout_contains<S: AsRef<str>>(&self, expected: S) -> &Self {
@@ -199,6 +216,13 @@ impl CompletedProcess {
         self
     }
 
+    /// Checks that `stdout` contains the regex pattern `expected`.
+    #[track_caller]
+    pub fn assert_stdout_contains_regex<S: AsRef<str>>(&self, expected: S) -> &Self {
+        assert_contains_regex(&self.stdout_utf8(), expected);
+        self
+    }
+
     /// Checks that trimmed `stderr` matches trimmed `expected`.
     #[track_caller]
     pub fn assert_stderr_equals<S: AsRef<str>>(&self, expected: S) -> &Self {
@@ -213,10 +237,24 @@ impl CompletedProcess {
         self
     }
 
+    /// Checks that `stderr` contains the regex pattern `expected`.
+    #[track_caller]
+    pub fn assert_stderr_contains_regex<S: AsRef<str>>(&self, expected: S) -> &Self {
+        assert_contains_regex(&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);
+        assert_not_contains(&self.stderr_utf8(), unexpected);
+        self
+    }
+
+    /// Checks that `stderr` does not contain the regex pattern `unexpected`.
+    #[track_caller]
+    pub fn assert_stderr_not_contains_regex<S: AsRef<str>>(&self, unexpected: S) -> &Self {
+        assert_not_contains_regex(&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 ac662331606..ee48e373366 100644
--- a/src/tools/run-make-support/src/diff/mod.rs
+++ b/src/tools/run-make-support/src/diff/mod.rs
@@ -1,10 +1,9 @@
 use std::path::{Path, PathBuf};
 
+use build_helper::drop_bomb::DropBomb;
 use regex::Regex;
 use similar::TextDiff;
 
-use build_helper::drop_bomb::DropBomb;
-
 use crate::fs;
 
 #[cfg(test)]
@@ -113,14 +112,8 @@ impl Diff {
         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::write(expected_file, actual);
-                    return;
-                }
+            if self.maybe_bless_expected_file(&actual) {
+                return;
             }
             panic!(
                 "test failed: `{}` is different from `{}`\n\n{}",
@@ -135,14 +128,8 @@ impl Diff {
         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::write(expected_file, actual);
-                    return;
-                }
+            if self.maybe_bless_expected_file(&actual) {
+                return;
             }
             panic!(
                 "test failed: `{}` is not different from `{}`\n\n{}",
@@ -150,4 +137,24 @@ impl Diff {
             )
         }
     }
+
+    /// If we have an expected file to write into, and `RUSTC_BLESS_TEST` is
+    /// set, then write the actual output into the file and return `true`.
+    ///
+    /// We assume that `RUSTC_BLESS_TEST` contains the path to the original test's
+    /// source directory. That lets us bless the original snapshot file in the
+    /// source tree, not the copy in `rmake_out` that we would normally use.
+    fn maybe_bless_expected_file(&self, actual: &str) -> bool {
+        let Some(ref expected_file) = self.expected_file else {
+            return false;
+        };
+        let Ok(bless_dir) = std::env::var("RUSTC_BLESS_TEST") else {
+            return false;
+        };
+
+        let bless_file = Path::new(&bless_dir).join(expected_file);
+        println!("Blessing `{}`", bless_file.display());
+        fs::write(bless_file, actual);
+        true
+    }
 }
diff --git a/src/tools/run-make-support/src/env.rs b/src/tools/run-make-support/src/env.rs
index f52524e7d54..e6460fb93d3 100644
--- a/src/tools/run-make-support/src/env.rs
+++ b/src/tools/run-make-support/src/env.rs
@@ -17,3 +17,10 @@ pub fn env_var_os(name: &str) -> OsString {
         None => panic!("failed to retrieve environment variable {name:?}"),
     }
 }
+
+/// Check if `NO_DEBUG_ASSERTIONS` is set (usually this may be set in CI jobs).
+#[track_caller]
+#[must_use]
+pub fn no_debug_assertions() -> bool {
+    std::env::var_os("NO_DEBUG_ASSERTIONS").is_some()
+}
diff --git a/src/tools/run-make-support/src/external_deps/c_build.rs b/src/tools/run-make-support/src/external_deps/c_build.rs
index 86c9c081831..f8d1666adda 100644
--- a/src/tools/run-make-support/src/external_deps/c_build.rs
+++ b/src/tools/run-make-support/src/external_deps/c_build.rs
@@ -1,8 +1,7 @@
 use std::path::PathBuf;
 
-use super::cygpath::get_windows_path;
 use crate::artifact_names::{dynamic_lib_name, static_lib_name};
-use crate::external_deps::cc::cc;
+use crate::external_deps::cc::{cc, cxx};
 use crate::external_deps::llvm::llvm_ar;
 use crate::path_helpers::path;
 use crate::targets::{is_darwin, is_msvc, is_windows};
@@ -10,16 +9,34 @@ use crate::targets::{is_darwin, is_msvc, is_windows};
 // FIXME(Oneirical): These native build functions should take a Path-based generic.
 
 /// Builds a static lib (`.lib` on Windows MSVC and `.a` for the rest) with the given name.
+/// Built from a C file.
 #[track_caller]
 pub fn build_native_static_lib(lib_name: &str) -> PathBuf {
+    build_native_static_lib_internal(lib_name, false)
+}
+
+/// Builds an optimized static lib (`.lib` on Windows MSVC and `.a` for the rest) with the given name.
+/// Built from a C file.
+#[track_caller]
+pub fn build_native_static_lib_optimized(lib_name: &str) -> PathBuf {
+    build_native_static_lib_internal(lib_name, true)
+}
+
+#[track_caller]
+fn build_native_static_lib_internal(lib_name: &str, optimzed: bool) -> PathBuf {
     let obj_file = if is_msvc() { format!("{lib_name}") } else { format!("{lib_name}.o") };
     let src = format!("{lib_name}.c");
     let lib_path = static_lib_name(lib_name);
-    if is_msvc() {
-        cc().arg("-c").out_exe(&obj_file).input(src).run();
-    } else {
-        cc().arg("-v").arg("-c").out_exe(&obj_file).input(src).run();
-    };
+
+    let mut cc = cc();
+    if !is_msvc() {
+        cc.arg("-v");
+    }
+    if optimzed {
+        cc.optimize();
+    }
+    cc.arg("-c").out_exe(&obj_file).input(src).optimize().run();
+
     let obj_file = if is_msvc() {
         PathBuf::from(format!("{lib_name}.obj"))
     } else {
@@ -43,8 +60,7 @@ pub fn build_native_dynamic_lib(lib_name: &str) -> PathBuf {
     };
     let obj_file = if is_msvc() { format!("{lib_name}.obj") } else { format!("{lib_name}.o") };
     if is_msvc() {
-        let mut out_arg = "-out:".to_owned();
-        out_arg.push_str(&get_windows_path(&lib_path));
+        let out_arg = format!("-out:{lib_path}");
         cc().input(&obj_file).args(&["-link", "-dll", &out_arg]).run();
     } else if is_darwin() {
         cc().out_exe(&lib_path).input(&obj_file).args(&["-dynamiclib", "-Wl,-dylib"]).run();
@@ -58,3 +74,24 @@ pub fn build_native_dynamic_lib(lib_name: &str) -> PathBuf {
     }
     path(lib_path)
 }
+
+/// Builds a static lib (`.lib` on Windows MSVC and `.a` for the rest) with the given name.
+/// Built from a C++ file.
+#[track_caller]
+pub fn build_native_static_lib_cxx(lib_name: &str) -> PathBuf {
+    let obj_file = if is_msvc() { format!("{lib_name}") } else { format!("{lib_name}.o") };
+    let src = format!("{lib_name}.cpp");
+    let lib_path = static_lib_name(lib_name);
+    if is_msvc() {
+        cxx().arg("-EHs").arg("-c").out_exe(&obj_file).input(src).run();
+    } else {
+        cxx().arg("-c").out_exe(&obj_file).input(src).run();
+    };
+    let obj_file = if is_msvc() {
+        PathBuf::from(format!("{lib_name}.obj"))
+    } else {
+        PathBuf::from(format!("{lib_name}.o"))
+    };
+    llvm_ar().obj_to_ar().output_input(&lib_path, &obj_file).run();
+    path(lib_path)
+}
diff --git a/src/tools/run-make-support/src/external_deps/cc.rs b/src/tools/run-make-support/src/external_deps/cc.rs
index 19a89705acc..011ad89e170 100644
--- a/src/tools/run-make-support/src/external_deps/cc.rs
+++ b/src/tools/run-make-support/src/external_deps/cc.rs
@@ -3,9 +3,6 @@ use std::path::Path;
 use crate::command::Command;
 use crate::{env_var, is_msvc, is_windows, uname};
 
-// FIXME(jieyouxu): can we get rid of the `cygpath` external dependency?
-use super::cygpath::get_windows_path;
-
 /// Construct a new platform-specific C compiler invocation.
 ///
 /// WARNING: This means that what flags are accepted by the underlying C compiler is
@@ -98,12 +95,12 @@ impl Cc {
 
         if is_msvc() {
             path.set_extension("exe");
-            let fe_path = get_windows_path(&path);
+            let fe_path = path.clone();
             path.set_extension("");
             path.set_extension("obj");
-            let fo_path = get_windows_path(path);
-            self.cmd.arg(format!("-Fe:{fe_path}"));
-            self.cmd.arg(format!("-Fo:{fo_path}"));
+            let fo_path = path;
+            self.cmd.arg(format!("-Fe:{}", fe_path.to_str().unwrap()));
+            self.cmd.arg(format!("-Fo:{}", fo_path.to_str().unwrap()));
         } else {
             self.cmd.arg("-o");
             self.cmd.arg(name);
@@ -118,6 +115,17 @@ impl Cc {
         self.cmd.arg(path.as_ref());
         self
     }
+
+    /// Optimize the output.
+    /// Equivalent to `-O3` for GNU-compatible linkers or `-O2` for MSVC linkers.
+    pub fn optimize(&mut self) -> &mut Self {
+        if is_msvc() {
+            self.cmd.arg("-O2");
+        } else {
+            self.cmd.arg("-O3");
+        }
+        self
+    }
 }
 
 /// `EXTRACFLAGS`
diff --git a/src/tools/run-make-support/src/external_deps/clang.rs b/src/tools/run-make-support/src/external_deps/clang.rs
index 2b0712541cd..2d110c6825e 100644
--- a/src/tools/run-make-support/src/external_deps/clang.rs
+++ b/src/tools/run-make-support/src/external_deps/clang.rs
@@ -1,7 +1,7 @@
 use std::path::Path;
 
 use crate::command::Command;
-use crate::{bin_name, env_var};
+use crate::{bin_name, cwd, env_var};
 
 /// Construct a new `clang` invocation. `clang` is not always available for all targets.
 #[track_caller]
@@ -23,7 +23,8 @@ impl Clang {
     #[track_caller]
     pub fn new() -> Self {
         let clang = env_var("CLANG");
-        let cmd = Command::new(clang);
+        let mut cmd = Command::new(clang);
+        cmd.arg("-L").arg(cwd());
         Self { cmd }
     }
 
diff --git a/src/tools/run-make-support/src/external_deps/cygpath.rs b/src/tools/run-make-support/src/external_deps/cygpath.rs
deleted file mode 100644
index 07d8e840a63..00000000000
--- a/src/tools/run-make-support/src/external_deps/cygpath.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-use std::panic;
-use std::path::Path;
-
-use crate::command::Command;
-use crate::util::handle_failed_output;
-
-/// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is
-/// available on the platform!
-///
-/// # FIXME
-///
-/// FIXME(jieyouxu): we should consider not depending on `cygpath`.
-///
-/// > The cygpath program is a utility that converts Windows native filenames to Cygwin POSIX-style
-/// > pathnames and vice versa.
-/// >
-/// > [irrelevant entries omitted...]
-/// >
-/// > `-w, --windows         print Windows form of NAMEs (C:\WINNT)`
-/// >
-/// > -- *from [cygpath documentation](https://cygwin.com/cygwin-ug-net/cygpath.html)*.
-#[track_caller]
-#[must_use]
-pub fn get_windows_path<P: AsRef<Path>>(path: P) -> String {
-    let caller = panic::Location::caller();
-    let mut cygpath = Command::new("cygpath");
-    cygpath.arg("-w");
-    cygpath.arg(path.as_ref());
-    let output = cygpath.run();
-    if !output.status().success() {
-        handle_failed_output(&cygpath, output, caller.line());
-    }
-    // cygpath -w can attach a newline
-    output.stdout_utf8().trim().to_string()
-}
diff --git a/src/tools/run-make-support/src/external_deps/htmldocck.rs b/src/tools/run-make-support/src/external_deps/htmldocck.rs
index afd0711ee04..621d386d85f 100644
--- a/src/tools/run-make-support/src/external_deps/htmldocck.rs
+++ b/src/tools/run-make-support/src/external_deps/htmldocck.rs
@@ -1,8 +1,7 @@
+use super::python::python_command;
 use crate::command::Command;
 use crate::source_root;
 
-use super::python::python_command;
-
 /// `htmldocck` is a python script which is used for rustdoc test suites, it is assumed to be
 /// available at `$SOURCE_ROOT/src/etc/htmldocck.py`.
 #[track_caller]
diff --git a/src/tools/run-make-support/src/external_deps/llvm.rs b/src/tools/run-make-support/src/external_deps/llvm.rs
index b116bd08e3a..dc651fdd820 100644
--- a/src/tools/run-make-support/src/external_deps/llvm.rs
+++ b/src/tools/run-make-support/src/external_deps/llvm.rs
@@ -36,6 +36,18 @@ pub fn llvm_ar() -> LlvmAr {
     LlvmAr::new()
 }
 
+/// Construct a new `llvm-nm` invocation. This assumes that `llvm-nm` is available
+/// at `$LLVM_BIN_DIR/llvm-nm`.
+pub fn llvm_nm() -> LlvmNm {
+    LlvmNm::new()
+}
+
+/// Construct a new `llvm-bcanalyzer` invocation. This assumes that `llvm-bcanalyzer` is available
+/// at `$LLVM_BIN_DIR/llvm-bcanalyzer`.
+pub fn llvm_bcanalyzer() -> LlvmBcanalyzer {
+    LlvmBcanalyzer::new()
+}
+
 /// A `llvm-readobj` invocation builder.
 #[derive(Debug)]
 #[must_use]
@@ -71,11 +83,27 @@ pub struct LlvmAr {
     cmd: Command,
 }
 
+/// A `llvm-nm` invocation builder.
+#[derive(Debug)]
+#[must_use]
+pub struct LlvmNm {
+    cmd: Command,
+}
+
+/// A `llvm-bcanalyzer` invocation builder.
+#[derive(Debug)]
+#[must_use]
+pub struct LlvmBcanalyzer {
+    cmd: Command,
+}
+
 crate::macros::impl_common_helpers!(LlvmReadobj);
 crate::macros::impl_common_helpers!(LlvmProfdata);
 crate::macros::impl_common_helpers!(LlvmFilecheck);
 crate::macros::impl_common_helpers!(LlvmObjdump);
 crate::macros::impl_common_helpers!(LlvmAr);
+crate::macros::impl_common_helpers!(LlvmNm);
+crate::macros::impl_common_helpers!(LlvmBcanalyzer);
 
 /// Generate the path to the bin directory of LLVM.
 #[must_use]
@@ -123,7 +151,8 @@ impl LlvmReadobj {
         self
     }
 
-    /// Pass `--symbols` to display the symbol.
+    /// Pass `--symbols` to display the symbol table, including both local
+    /// and global symbols.
     pub fn symbols(&mut self) -> &mut Self {
         self.cmd.arg("--symbols");
         self
@@ -218,6 +247,12 @@ impl LlvmObjdump {
         self.cmd.arg(path.as_ref());
         self
     }
+
+    /// Disassemble all executable sections found in the input files.
+    pub fn disassemble(&mut self) -> &mut Self {
+        self.cmd.arg("-d");
+        self
+    }
 }
 
 impl LlvmAr {
@@ -236,6 +271,12 @@ impl LlvmAr {
         self
     }
 
+    /// Extract archive members back to files.
+    pub fn extract(&mut self) -> &mut Self {
+        self.cmd.arg("x");
+        self
+    }
+
     /// Provide an output, then an input file. Bundled in one function, as llvm-ar has
     /// no "--output"-style flag.
     pub fn output_input(&mut self, out: impl AsRef<Path>, input: impl AsRef<Path>) -> &mut Self {
@@ -244,3 +285,35 @@ impl LlvmAr {
         self
     }
 }
+
+impl LlvmNm {
+    /// Construct a new `llvm-nm` invocation. This assumes that `llvm-nm` is available
+    /// at `$LLVM_BIN_DIR/llvm-nm`.
+    pub fn new() -> Self {
+        let llvm_nm = llvm_bin_dir().join("llvm-nm");
+        let cmd = Command::new(llvm_nm);
+        Self { cmd }
+    }
+
+    /// Provide an input file.
+    pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
+        self.cmd.arg(path.as_ref());
+        self
+    }
+}
+
+impl LlvmBcanalyzer {
+    /// Construct a new `llvm-bcanalyzer` invocation. This assumes that `llvm-bcanalyzer` is available
+    /// at `$LLVM_BIN_DIR/llvm-bcanalyzer`.
+    pub fn new() -> Self {
+        let llvm_bcanalyzer = llvm_bin_dir().join("llvm-bcanalyzer");
+        let cmd = Command::new(llvm_bcanalyzer);
+        Self { cmd }
+    }
+
+    /// Provide an input file.
+    pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
+        self.cmd.arg(path.as_ref());
+        self
+    }
+}
diff --git a/src/tools/run-make-support/src/external_deps/mod.rs b/src/tools/run-make-support/src/external_deps/mod.rs
index a2dc426f3f2..f7c84724d0e 100644
--- a/src/tools/run-make-support/src/external_deps/mod.rs
+++ b/src/tools/run-make-support/src/external_deps/mod.rs
@@ -9,6 +9,3 @@ pub mod llvm;
 pub mod python;
 pub mod rustc;
 pub mod rustdoc;
-
-// Library-internal external dependency.
-mod cygpath;
diff --git a/src/tools/run-make-support/src/external_deps/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs
index 71d28dd9675..cece58d2956 100644
--- a/src/tools/run-make-support/src/external_deps/rustc.rs
+++ b/src/tools/run-make-support/src/external_deps/rustc.rs
@@ -5,6 +5,7 @@ use crate::command::Command;
 use crate::env::env_var;
 use crate::path_helpers::cwd;
 use crate::util::set_host_rpath;
+use crate::{is_darwin, is_msvc, is_windows, uname};
 
 /// Construct a new `rustc` invocation. This will automatically set the library
 /// search path as `-L cwd()`. Use [`bare_rustc`] to avoid this.
@@ -314,4 +315,62 @@ impl Rustc {
         self.cmd.arg(format!("-Clinker-flavor={linker_flavor}"));
         self
     }
+
+    /// `EXTRARSCXXFLAGS`
+    pub fn extra_rs_cxx_flags(&mut self) -> &mut Self {
+        // Adapted from tools.mk (trimmed):
+        //
+        // ```makefile
+        // ifdef IS_WINDOWS
+        //     ifdef IS_MSVC
+        //     else
+        //         EXTRARSCXXFLAGS := -lstatic:-bundle=stdc++
+        //     endif
+        // else
+        //     ifeq ($(UNAME),Darwin)
+        //         EXTRARSCXXFLAGS := -lc++
+        //     else
+        //         ifeq ($(UNAME),FreeBSD)
+        //         else
+        //             ifeq ($(UNAME),SunOS)
+        //             else
+        //                 ifeq ($(UNAME),OpenBSD)
+        //                 else
+        //                     EXTRARSCXXFLAGS := -lstdc++
+        //                 endif
+        //             endif
+        //         endif
+        //     endif
+        // endif
+        // ```
+        let flag = if is_windows() {
+            // So this is a bit hacky: we can't use the DLL version of libstdc++ because
+            // it pulls in the DLL version of libgcc, which means that we end up with 2
+            // instances of the DW2 unwinding implementation. This is a problem on
+            // i686-pc-windows-gnu because each module (DLL/EXE) needs to register its
+            // unwind information with the unwinding implementation, and libstdc++'s
+            // __cxa_throw won't see the unwinding info we registered with our statically
+            // linked libgcc.
+            //
+            // Now, simply statically linking libstdc++ would fix this problem, except
+            // that it is compiled with the expectation that pthreads is dynamically
+            // linked as a DLL and will fail to link with a statically linked libpthread.
+            //
+            // So we end up with the following hack: we link use static:-bundle to only
+            // link the parts of libstdc++ that we actually use, which doesn't include
+            // the dependency on the pthreads DLL.
+            if is_msvc() { None } else { Some("-lstatic:-bundle=stdc++") }
+        } else if is_darwin() {
+            Some("-lc++")
+        } else {
+            match &uname()[..] {
+                "FreeBSD" | "SunOS" | "OpenBSD" => None,
+                _ => Some("-lstdc++"),
+            }
+        };
+        if let Some(flag) = flag {
+            self.cmd.arg(flag);
+        }
+        self
+    }
 }
diff --git a/src/tools/run-make-support/src/fs.rs b/src/tools/run-make-support/src/fs.rs
index 0a796161633..2c35ba52a62 100644
--- a/src/tools/run-make-support/src/fs.rs
+++ b/src/tools/run-make-support/src/fs.rs
@@ -9,11 +9,19 @@ pub fn create_symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) {
     if link.as_ref().exists() {
         std::fs::remove_dir(link.as_ref()).unwrap();
     }
-    std::os::windows::fs::symlink_file(original.as_ref(), link.as_ref()).expect(&format!(
-        "failed to create symlink {:?} for {:?}",
-        link.as_ref().display(),
-        original.as_ref().display(),
-    ));
+    if original.as_ref().is_file() {
+        std::os::windows::fs::symlink_file(original.as_ref(), link.as_ref()).expect(&format!(
+            "failed to create symlink {:?} for {:?}",
+            link.as_ref().display(),
+            original.as_ref().display(),
+        ));
+    } else {
+        std::os::windows::fs::symlink_dir(original.as_ref(), link.as_ref()).expect(&format!(
+            "failed to create symlink {:?} for {:?}",
+            link.as_ref().display(),
+            original.as_ref().display(),
+        ));
+    }
 }
 
 /// Creates a new symlink to a path on the filesystem, adjusting for Windows or Unix.
@@ -41,6 +49,8 @@ pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
             let ty = entry.file_type()?;
             if ty.is_dir() {
                 copy_dir_all_inner(entry.path(), dst.join(entry.file_name()))?;
+            } else if ty.is_symlink() {
+                copy_symlink(entry.path(), dst.join(entry.file_name()))?;
             } else {
                 std::fs::copy(entry.path(), dst.join(entry.file_name()))?;
             }
@@ -59,6 +69,12 @@ pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
     }
 }
 
+fn copy_symlink<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
+    let target_path = std::fs::read_link(from).unwrap();
+    create_symlink(target_path, to);
+    Ok(())
+}
+
 /// Helper for reading entries in a given directory.
 pub fn read_dir_entries<P: AsRef<Path>, F: FnMut(&Path)>(dir: P, mut callback: F) {
     for entry in read_dir(dir) {
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index 085120764b4..a44dd00ad79 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -21,6 +21,7 @@ pub mod run;
 pub mod scoped_run;
 pub mod string;
 pub mod targets;
+pub mod symbols;
 
 // Internally we call our fs-related support module as `fs`, but re-export its content as `rfs`
 // to tests to avoid colliding with commonly used `use std::fs;`.
@@ -43,13 +44,13 @@ pub use wasmparser;
 pub use external_deps::{c_build, cc, clang, htmldocck, llvm, python, rustc, rustdoc};
 
 // These rely on external dependencies.
-pub use c_build::{build_native_dynamic_lib, build_native_static_lib};
 pub use cc::{cc, cxx, extra_c_flags, extra_cxx_flags, Cc};
+pub use c_build::{build_native_dynamic_lib, build_native_static_lib, build_native_static_lib_optimized, build_native_static_lib_cxx};
 pub use clang::{clang, Clang};
 pub use htmldocck::htmldocck;
 pub use llvm::{
-    llvm_ar, llvm_filecheck, llvm_objdump, llvm_profdata, llvm_readobj, LlvmAr, LlvmFilecheck,
-    LlvmObjdump, LlvmProfdata, LlvmReadobj,
+    llvm_ar, llvm_bcanalyzer, llvm_filecheck, llvm_nm, llvm_objdump, llvm_profdata, llvm_readobj,
+    LlvmAr, LlvmBcanalyzer, LlvmFilecheck, LlvmNm, LlvmObjdump, LlvmProfdata, LlvmReadobj,
 };
 pub use python::python_command;
 pub use rustc::{aux_build, bare_rustc, rustc, Rustc};
@@ -71,20 +72,22 @@ pub use targets::{is_darwin, is_msvc, is_windows, llvm_components_contain, targe
 
 /// Helpers for building names of output artifacts that are potentially target-specific.
 pub use artifact_names::{
-    bin_name, dynamic_lib_extension, dynamic_lib_name, rust_lib_name, static_lib_name,
+    bin_name, dynamic_lib_extension, dynamic_lib_name, msvc_import_dynamic_lib_name, rust_lib_name,
+    static_lib_name,
 };
 
 /// Path-related helpers.
 pub use path_helpers::{
-    cwd, filename_not_in_denylist, has_extension, has_prefix, has_suffix, not_contains, path,
-    shallow_find_files, source_root,
+    cwd, filename_contains, filename_not_in_denylist, has_extension, has_prefix, has_suffix,
+    not_contains, path, shallow_find_files, source_root,
 };
 
 /// Helpers for scoped test execution where certain properties are attempted to be maintained.
 pub use scoped_run::{run_in_tmpdir, test_while_readonly};
 
 pub use assertion_helpers::{
-    assert_contains, assert_dirs_are_equal, assert_equals, assert_not_contains,
+    assert_contains, assert_contains_regex, assert_dirs_are_equal, assert_equals,
+    assert_not_contains, assert_not_contains_regex,
 };
 
 pub use string::{
diff --git a/src/tools/run-make-support/src/path_helpers.rs b/src/tools/run-make-support/src/path_helpers.rs
index f37ea8dfef8..b788bc6ef30 100644
--- a/src/tools/run-make-support/src/path_helpers.rs
+++ b/src/tools/run-make-support/src/path_helpers.rs
@@ -3,6 +3,7 @@
 use std::path::{Path, PathBuf};
 
 use crate::env::env_var;
+use crate::rfs;
 
 /// Return the current working directory.
 ///
@@ -40,7 +41,7 @@ pub fn shallow_find_files<P: AsRef<Path>, F: Fn(&PathBuf) -> bool>(
     filter: F,
 ) -> Vec<PathBuf> {
     let mut matching_files = Vec::new();
-    for entry in std::fs::read_dir(path).unwrap() {
+    for entry in rfs::read_dir(path) {
         let entry = entry.expect("failed to read directory entry.");
         let path = entry.path();
 
@@ -78,3 +79,8 @@ pub fn has_extension<P: AsRef<Path>>(path: P, extension: &str) -> bool {
 pub fn has_suffix<P: AsRef<Path>>(path: P, suffix: &str) -> bool {
     path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().ends_with(suffix))
 }
+
+/// Returns true if the filename at `path` contains `needle`.
+pub fn filename_contains<P: AsRef<Path>>(path: P, needle: &str) -> bool {
+    path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().contains(needle))
+}
diff --git a/src/tools/run-make-support/src/run.rs b/src/tools/run-make-support/src/run.rs
index 17f8ce34f19..12088e5d3b5 100644
--- a/src/tools/run-make-support/src/run.rs
+++ b/src/tools/run-make-support/src/run.rs
@@ -1,7 +1,6 @@
-use std::env;
 use std::ffi::OsStr;
-use std::panic;
 use std::path::{Path, PathBuf};
+use std::{env, panic};
 
 use crate::command::{Command, CompletedProcess};
 use crate::util::{handle_failed_output, set_host_rpath};
diff --git a/src/tools/run-make-support/src/symbols.rs b/src/tools/run-make-support/src/symbols.rs
new file mode 100644
index 00000000000..fd0c866bcc9
--- /dev/null
+++ b/src/tools/run-make-support/src/symbols.rs
@@ -0,0 +1,44 @@
+use std::path::Path;
+
+use object::{self, Object, ObjectSymbol, SymbolIterator};
+
+/// Iterate through the symbols in an object file.
+///
+/// Uses a callback because `SymbolIterator` does not own its data.
+///
+/// Panics if `path` is not a valid object file readable by the current user.
+pub fn with_symbol_iter<P, F, R>(path: P, func: F) -> R
+where
+    P: AsRef<Path>,
+    F: FnOnce(&mut SymbolIterator<'_, '_>) -> R,
+{
+    let raw_bytes = crate::fs::read(path);
+    let f = object::File::parse(raw_bytes.as_slice()).expect("unable to parse file");
+    let mut iter = f.symbols();
+    func(&mut iter)
+}
+
+/// Check an object file's symbols for substrings.
+///
+/// Returns `true` if any of the symbols found in the object file at
+/// `path` contain a substring listed in `substrings`.
+///
+/// Panics if `path` is not a valid object file readable by the current user.
+pub fn any_symbol_contains(path: impl AsRef<Path>, substrings: &[&str]) -> bool {
+    with_symbol_iter(path, |syms| {
+        for sym in syms {
+            for substring in substrings {
+                if sym
+                    .name_bytes()
+                    .unwrap()
+                    .windows(substring.len())
+                    .any(|x| x == substring.as_bytes())
+                {
+                    eprintln!("{:?} contains {}", sym, substring);
+                    return true;
+                }
+            }
+        }
+        false
+    })
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
index bd43a62341d..d76f5381871 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
@@ -27,6 +27,7 @@ macro_rules! from_bytes {
     ($ty:tt, $value:expr) => {
         ($ty::from_le_bytes(match ($value).try_into() {
             Ok(it) => it,
+            #[allow(unreachable_patterns)]
             Err(_) => return Err(MirEvalError::InternalError("mismatched size".into())),
         }))
     };
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
index 057f5533805..9aa2eeebc17 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
@@ -1161,6 +1161,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
                                     ProjectionElem::OpaqueCast(it) => {
                                         ProjectionElem::OpaqueCast(it)
                                     }
+                                    #[allow(unreachable_patterns)]
                                     ProjectionElem::Index(it) => match it {},
                                 })
                                 .collect(),
diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version
index 001b900b207..d4f1703d850 100644
--- a/src/tools/rust-analyzer/rust-version
+++ b/src/tools/rust-analyzer/rust-version
@@ -1 +1 @@
-1b51d80027919563004918eaadfa0d890ac0eb93
+80eb5a8e910e5185d47cdefe3732d839c78a5e7e
diff --git a/src/tools/rust-installer/src/combiner.rs b/src/tools/rust-installer/src/combiner.rs
index e7020980dc3..66b3d324568 100644
--- a/src/tools/rust-installer/src/combiner.rs
+++ b/src/tools/rust-installer/src/combiner.rs
@@ -1,14 +1,13 @@
-use super::Scripter;
-use super::Tarballer;
-use crate::{
-    compression::{CompressionFormat, CompressionFormats, CompressionProfile},
-    util::*,
-};
-use anyhow::{bail, Context, Result};
 use std::io::{Read, Write};
 use std::path::Path;
+
+use anyhow::{bail, Context, Result};
 use tar::Archive;
 
+use super::{Scripter, Tarballer};
+use crate::compression::{CompressionFormat, CompressionFormats, CompressionProfile};
+use crate::util::*;
+
 actor! {
     #[derive(Debug)]
     pub struct Combiner {
diff --git a/src/tools/rust-installer/src/compression.rs b/src/tools/rust-installer/src/compression.rs
index 40c7c597e9b..df3a98ae789 100644
--- a/src/tools/rust-installer/src/compression.rs
+++ b/src/tools/rust-installer/src/compression.rs
@@ -1,8 +1,14 @@
+use std::fmt;
+use std::io::{Read, Write};
+use std::path::Path;
+use std::str::FromStr;
+
 use anyhow::{Context, Error};
-use flate2::{read::GzDecoder, write::GzEncoder};
+use flate2::read::GzDecoder;
+use flate2::write::GzEncoder;
 use rayon::prelude::*;
-use std::{fmt, io::Read, io::Write, path::Path, str::FromStr};
-use xz2::{read::XzDecoder, write::XzEncoder};
+use xz2::read::XzDecoder;
+use xz2::write::XzEncoder;
 
 #[derive(Default, Debug, Copy, Clone)]
 pub enum CompressionProfile {
diff --git a/src/tools/rust-installer/src/generator.rs b/src/tools/rust-installer/src/generator.rs
index 035a394deeb..e1228693344 100644
--- a/src/tools/rust-installer/src/generator.rs
+++ b/src/tools/rust-installer/src/generator.rs
@@ -1,12 +1,13 @@
-use super::Scripter;
-use super::Tarballer;
-use crate::compression::{CompressionFormats, CompressionProfile};
-use crate::util::*;
-use anyhow::{bail, format_err, Context, Result};
 use std::collections::BTreeSet;
 use std::io::Write;
 use std::path::Path;
 
+use anyhow::{bail, format_err, Context, Result};
+
+use super::{Scripter, Tarballer};
+use crate::compression::{CompressionFormats, CompressionProfile};
+use crate::util::*;
+
 actor! {
     #[derive(Debug)]
     pub struct Generator {
diff --git a/src/tools/rust-installer/src/scripter.rs b/src/tools/rust-installer/src/scripter.rs
index ff65e818b09..abac405050c 100644
--- a/src/tools/rust-installer/src/scripter.rs
+++ b/src/tools/rust-installer/src/scripter.rs
@@ -1,7 +1,9 @@
-use crate::util::*;
-use anyhow::{Context, Result};
 use std::io::Write;
 
+use anyhow::{Context, Result};
+
+use crate::util::*;
+
 const TEMPLATE: &str = include_str!("../install-template.sh");
 
 actor! {
diff --git a/src/tools/rust-installer/src/tarballer.rs b/src/tools/rust-installer/src/tarballer.rs
index b5e87a66ffc..a101be8f5ff 100644
--- a/src/tools/rust-installer/src/tarballer.rs
+++ b/src/tools/rust-installer/src/tarballer.rs
@@ -1,14 +1,13 @@
-use anyhow::{bail, Context, Result};
 use std::fs::{read_link, symlink_metadata};
 use std::io::{BufWriter, Write};
 use std::path::Path;
+
+use anyhow::{bail, Context, Result};
 use tar::{Builder, Header, HeaderMode};
 use walkdir::WalkDir;
 
-use crate::{
-    compression::{CombinedEncoder, CompressionFormats, CompressionProfile},
-    util::*,
-};
+use crate::compression::{CombinedEncoder, CompressionFormats, CompressionProfile};
+use crate::util::*;
 
 actor! {
     #[derive(Debug)]
diff --git a/src/tools/rust-installer/src/util.rs b/src/tools/rust-installer/src/util.rs
index 47ca0cfa3cc..51b8c9c9d1b 100644
--- a/src/tools/rust-installer/src/util.rs
+++ b/src/tools/rust-installer/src/util.rs
@@ -1,17 +1,16 @@
-use anyhow::{format_err, Context, Result};
 use std::fs;
-use std::path::Path;
-use walkdir::WalkDir;
-
-// Needed to set the script mode to executable.
-#[cfg(unix)]
-use std::os::unix::fs::OpenOptionsExt;
 // FIXME: what about Windows? Are default ACLs executable?
-
 #[cfg(unix)]
 use std::os::unix::fs::symlink as symlink_file;
+// Needed to set the script mode to executable.
+#[cfg(unix)]
+use std::os::unix::fs::OpenOptionsExt;
 #[cfg(windows)]
 use std::os::windows::fs::symlink_file;
+use std::path::Path;
+
+use anyhow::{format_err, Context, Result};
+use walkdir::WalkDir;
 
 /// Converts a `&Path` to a UTF-8 `&str`.
 pub fn path_to_str(path: &Path) -> Result<&str> {
diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock
index 75b89a162e9..df051ed447e 100644
--- a/src/tools/rustbook/Cargo.lock
+++ b/src/tools/rustbook/Cargo.lock
@@ -662,6 +662,20 @@ dependencies = [
 ]
 
 [[package]]
+name = "mdbook-spec"
+version = "0.1.2"
+dependencies = [
+ "anyhow",
+ "mdbook",
+ "once_cell",
+ "pathdiff",
+ "regex",
+ "semver",
+ "serde_json",
+ "tempfile",
+]
+
+[[package]]
 name = "mdbook-trpl-listing"
 version = "0.1.0"
 dependencies = [
@@ -795,6 +809,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "pathdiff"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
+
+[[package]]
 name = "percent-encoding"
 version = "2.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1079,6 +1099,7 @@ dependencies = [
  "env_logger",
  "mdbook",
  "mdbook-i18n-helpers",
+ "mdbook-spec",
  "mdbook-trpl-listing",
  "mdbook-trpl-note",
 ]
diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml
index 51ba58483c5..2c29a2848b7 100644
--- a/src/tools/rustbook/Cargo.toml
+++ b/src/tools/rustbook/Cargo.toml
@@ -12,6 +12,7 @@ env_logger = "0.11"
 mdbook-trpl-listing = { path = "../../doc/book/packages/mdbook-trpl-listing" }
 mdbook-trpl-note = { path = "../../doc/book/packages/mdbook-trpl-note" }
 mdbook-i18n-helpers = "0.3.3"
+mdbook-spec = { path = "../../doc/reference/mdbook-spec"}
 
 [dependencies.mdbook]
 version = "0.4.37"
diff --git a/src/tools/rustbook/src/main.rs b/src/tools/rustbook/src/main.rs
index 31bba56adde..a4faac0760f 100644
--- a/src/tools/rustbook/src/main.rs
+++ b/src/tools/rustbook/src/main.rs
@@ -1,14 +1,11 @@
-use clap::crate_version;
-
 use std::env;
 use std::path::{Path, PathBuf};
 
-use clap::{arg, ArgMatches, Command};
-
+use clap::{arg, crate_version, ArgMatches, Command};
 use mdbook::errors::Result as Result3;
 use mdbook::MDBook;
 use mdbook_i18n_helpers::preprocessors::Gettext;
-
+use mdbook_spec::Spec;
 use mdbook_trpl_listing::TrplListing;
 use mdbook_trpl_note::TrplNote;
 
@@ -83,6 +80,13 @@ pub fn build(args: &ArgMatches) -> Result3<()> {
         book.config.build.build_dir = dest_dir.into();
     }
 
+    // NOTE: Replacing preprocessors using this technique causes error
+    // messages to be displayed when the original preprocessor doesn't work
+    // (but it otherwise succeeds).
+    //
+    // This should probably be fixed in mdbook to remove the existing
+    // preprocessor, or this should modify the config and use
+    // MDBook::load_with_config.
     if book.config.get_preprocessor("trpl-note").is_some() {
         book.with_preprocessor(TrplNote);
     }
@@ -91,6 +95,10 @@ pub fn build(args: &ArgMatches) -> Result3<()> {
         book.with_preprocessor(TrplListing);
     }
 
+    if book.config.get_preprocessor("spec").is_some() {
+        book.with_preprocessor(Spec::new());
+    }
+
     book.build()?;
 
     Ok(())
diff --git a/src/tools/rustc-perf b/src/tools/rustc-perf
-Subproject c64bb60dd1636922b1ccbb82867bed934a99dbc
+Subproject d5055e78042c739deeb3fe0bef83fde0e5cc259
diff --git a/src/tools/rustc-perf-wrapper/src/main.rs b/src/tools/rustc-perf-wrapper/src/main.rs
index 1c0d1745f3d..951d36b788b 100644
--- a/src/tools/rustc-perf-wrapper/src/main.rs
+++ b/src/tools/rustc-perf-wrapper/src/main.rs
@@ -1,8 +1,11 @@
-use crate::config::{Profile, Scenario};
-use clap::Parser;
+use std::fs::create_dir_all;
 use std::path::PathBuf;
 use std::process::Command;
 
+use clap::Parser;
+
+use crate::config::{Profile, Scenario};
+
 mod config;
 
 /// Performs profiling or benchmarking with [`rustc-perf`](https://github.com/rust-lang/rustc-perf)
@@ -16,9 +19,6 @@ pub struct Args {
     cmd: PerfCommand,
 
     #[clap(flatten)]
-    opts: SharedOpts,
-
-    #[clap(flatten)]
     ctx: BuildContext,
 }
 
@@ -26,22 +26,37 @@ pub struct Args {
 enum PerfCommand {
     /// Run `profile_local eprintln`.
     /// This executes the compiler on the given benchmarks and stores its stderr output.
-    Eprintln,
+    Eprintln {
+        #[clap(flatten)]
+        opts: SharedOpts,
+    },
     /// 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,
+    Samply {
+        #[clap(flatten)]
+        opts: SharedOpts,
+    },
     /// 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,
-        }
-    }
+    Cachegrind {
+        #[clap(flatten)]
+        opts: SharedOpts,
+    },
+    Benchmark {
+        /// Identifier to associate benchmark results with
+        id: String,
+
+        #[clap(flatten)]
+        opts: SharedOpts,
+    },
+    Compare {
+        /// The name of the base artifact to be compared.
+        base: String,
+
+        /// The name of the modified artifact to be compared.
+        modified: String,
+    },
 }
 
 #[derive(Debug, clap::Parser)]
@@ -50,6 +65,11 @@ struct SharedOpts {
     /// If unspecified, all benchmarks will be executed.
     #[clap(long, global = true, value_delimiter = ',')]
     include: Vec<String>,
+
+    /// Select the benchmarks matching a prefix in this comma-separated list that you don't want to run.
+    #[clap(long, global = true, value_delimiter = ',')]
+    exclude: Vec<String>,
+
     /// Select the scenarios that should be benchmarked.
     #[clap(
         long,
@@ -85,35 +105,67 @@ fn main() {
 
 fn run(args: Args) {
     let mut cmd = Command::new(args.ctx.collector);
+    let db_path = args.ctx.results_dir.join("results.db");
+
     match &args.cmd {
-        PerfCommand::Eprintln => {
-            cmd.arg("profile_local").arg("eprintln");
+        PerfCommand::Eprintln { opts }
+        | PerfCommand::Samply { opts }
+        | PerfCommand::Cachegrind { opts } => {
+            cmd.arg("profile_local");
+            cmd.arg(match &args.cmd {
+                PerfCommand::Eprintln { .. } => "eprintln",
+                PerfCommand::Samply { .. } => "samply",
+                PerfCommand::Cachegrind { .. } => "cachegrind",
+                _ => unreachable!(),
+            });
+
+            cmd.arg("--out-dir").arg(&args.ctx.results_dir);
+
+            apply_shared_opts(&mut cmd, opts);
+            execute_benchmark(&mut cmd, &args.ctx.compiler);
+
+            println!("You can find the results at `{}`", args.ctx.results_dir.display());
         }
-        PerfCommand::Samply => {
-            cmd.arg("profile_local").arg("samply");
+        PerfCommand::Benchmark { id, opts } => {
+            cmd.arg("bench_local");
+            cmd.arg("--db").arg(&db_path);
+            cmd.arg("--id").arg(id);
+
+            apply_shared_opts(&mut cmd, opts);
+            create_dir_all(&args.ctx.results_dir).unwrap();
+            execute_benchmark(&mut cmd, &args.ctx.compiler);
         }
-        PerfCommand::Cachegrind => {
-            cmd.arg("profile_local").arg("cachegrind");
+        PerfCommand::Compare { base, modified } => {
+            cmd.arg("bench_cmp");
+            cmd.arg("--db").arg(&db_path);
+            cmd.arg(base).arg(modified);
+
+            create_dir_all(&args.ctx.results_dir).unwrap();
+            cmd.status().expect("error while running rustc-perf bench_cmp");
         }
     }
-    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(","));
+fn apply_shared_opts(cmd: &mut Command, opts: &SharedOpts) {
+    if !opts.include.is_empty() {
+        cmd.arg("--include").arg(opts.include.join(","));
+    }
+    if !opts.exclude.is_empty() {
+        cmd.arg("--exclude").arg(opts.exclude.join(","));
     }
-    if !args.opts.profiles.is_empty() {
+    if !opts.profiles.is_empty() {
         cmd.arg("--profiles")
-            .arg(args.opts.profiles.iter().map(|p| p.to_string()).collect::<Vec<_>>().join(","));
+            .arg(opts.profiles.iter().map(|p| p.to_string()).collect::<Vec<_>>().join(","));
     }
-    if !args.opts.scenarios.is_empty() {
+    if !opts.scenarios.is_empty() {
         cmd.arg("--scenarios")
-            .arg(args.opts.scenarios.iter().map(|p| p.to_string()).collect::<Vec<_>>().join(","));
+            .arg(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());
+fn execute_benchmark(cmd: &mut Command, compiler: &PathBuf) {
+    cmd.arg(compiler);
+    println!("Running `rustc-perf` using `{}`", compiler.display());
 
     const MANIFEST_DIR: &str = env!("CARGO_MANIFEST_DIR");
 
@@ -123,8 +175,4 @@ fn run(args: Args) {
     // 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/rustdoc-gui-test/src/config.rs b/src/tools/rustdoc-gui-test/src/config.rs
index dc4c56a5e7a..950e2fa478d 100644
--- a/src/tools/rustdoc-gui-test/src/config.rs
+++ b/src/tools/rustdoc-gui-test/src/config.rs
@@ -1,5 +1,7 @@
+use std::env;
+use std::path::PathBuf;
+
 use getopts::Options;
-use std::{env, path::PathBuf};
 
 pub(crate) struct Config {
     pub(crate) nodejs: PathBuf,
diff --git a/src/tools/rustdoc-gui-test/src/main.rs b/src/tools/rustdoc-gui-test/src/main.rs
index bf581279f2a..5adb525d7e6 100644
--- a/src/tools/rustdoc-gui-test/src/main.rs
+++ b/src/tools/rustdoc-gui-test/src/main.rs
@@ -1,11 +1,12 @@
-use build_helper::util::try_run;
-use compiletest::header::TestProps;
-use config::Config;
 use std::path::{Path, PathBuf};
 use std::process::Command;
 use std::sync::Arc;
 use std::{env, fs};
 
+use build_helper::util::try_run;
+use compiletest::header::TestProps;
+use config::Config;
+
 mod config;
 
 fn get_browser_ui_test_version_inner(npm: &Path, global: bool) -> Option<String> {
diff --git a/src/tools/rustdoc/main.rs b/src/tools/rustdoc/main.rs
index 5b499a1fa1f..d4099cafe5d 100644
--- a/src/tools/rustdoc/main.rs
+++ b/src/tools/rustdoc/main.rs
@@ -1,3 +1,6 @@
+// We need this feature as it changes `dylib` linking behavior and allows us to link to `rustc_driver`.
+#![feature(rustc_private)]
+
 fn main() {
     rustdoc::main()
 }
diff --git a/src/tools/rustfmt/src/git-rustfmt/main.rs b/src/tools/rustfmt/src/git-rustfmt/main.rs
index 3059d917c6b..5674f40bef9 100644
--- a/src/tools/rustfmt/src/git-rustfmt/main.rs
+++ b/src/tools/rustfmt/src/git-rustfmt/main.rs
@@ -1,3 +1,7 @@
+// We need this feature as it changes `dylib` linking behavior and allows us to link to
+// `rustc_driver`.
+#![feature(rustc_private)]
+
 #[macro_use]
 extern crate tracing;
 
diff --git a/src/tools/rustfmt/src/parse/macros/lazy_static.rs b/src/tools/rustfmt/src/parse/macros/lazy_static.rs
index 7baac247e22..b6de5f8691c 100644
--- a/src/tools/rustfmt/src/parse/macros/lazy_static.rs
+++ b/src/tools/rustfmt/src/parse/macros/lazy_static.rs
@@ -33,15 +33,17 @@ pub(crate) fn parse_lazy_static(
     }
     while parser.token.kind != TokenKind::Eof {
         // Parse a `lazy_static!` item.
+        // FIXME: These `eat_*` calls should be converted to `parse_or` to avoid
+        // silently formatting malformed lazy-statics.
         let vis = parse_or!(parse_visibility, rustc_parse::parser::FollowedByType::No);
-        parser.eat_keyword(kw::Static);
-        parser.eat_keyword(kw::Ref);
+        let _ = parser.eat_keyword(kw::Static);
+        let _ = parser.eat_keyword(kw::Ref);
         let id = parse_or!(parse_ident);
-        parser.eat(&TokenKind::Colon);
+        let _ = parser.eat(&TokenKind::Colon);
         let ty = parse_or!(parse_ty);
-        parser.eat(&TokenKind::Eq);
+        let _ = parser.eat(&TokenKind::Eq);
         let expr = parse_or!(parse_expr);
-        parser.eat(&TokenKind::Semi);
+        let _ = parser.eat(&TokenKind::Semi);
         result.push((vis, id, ty, expr));
     }
 
diff --git a/src/tools/rustfmt/tests/source/cfg_if/detect/os/x86.rs b/src/tools/rustfmt/tests/source/cfg_if/detect/os/x86.rs
index 9257b8a4be6..b9adc67221a 100644
--- a/src/tools/rustfmt/tests/source/cfg_if/detect/os/x86.rs
+++ b/src/tools/rustfmt/tests/source/cfg_if/detect/os/x86.rs
@@ -34,15 +34,6 @@ pub fn check_for(x: Feature) -> bool {
 fn detect_features() -> cache::Initializer {
     let mut value = cache::Initializer::default();
 
-    // If the x86 CPU does not support the CPUID instruction then it is too
-    // old to support any of the currently-detectable features.
-    if !has_cpuid() {
-        return value;
-    }
-
-    // Calling `__cpuid`/`__cpuid_count` from here on is safe because the CPU
-    // has `cpuid` support.
-
     // 0. EAX = 0: Basic Information:
     // - EAX returns the "Highest Function Parameter", that is, the maximum
     // leaf value for subsequent calls of `cpuinfo` in range [0,
diff --git a/src/tools/rustfmt/tests/target/cfg_if/detect/os/x86.rs b/src/tools/rustfmt/tests/target/cfg_if/detect/os/x86.rs
index 2e228aa3745..944b51615f8 100644
--- a/src/tools/rustfmt/tests/target/cfg_if/detect/os/x86.rs
+++ b/src/tools/rustfmt/tests/target/cfg_if/detect/os/x86.rs
@@ -34,15 +34,6 @@ pub fn check_for(x: Feature) -> bool {
 fn detect_features() -> cache::Initializer {
     let mut value = cache::Initializer::default();
 
-    // If the x86 CPU does not support the CPUID instruction then it is too
-    // old to support any of the currently-detectable features.
-    if !has_cpuid() {
-        return value;
-    }
-
-    // Calling `__cpuid`/`__cpuid_count` from here on is safe because the CPU
-    // has `cpuid` support.
-
     // 0. EAX = 0: Basic Information:
     // - EAX returns the "Highest Function Parameter", that is, the maximum
     // leaf value for subsequent calls of `cpuinfo` in range [0,
diff --git a/src/tools/suggest-tests/src/lib.rs b/src/tools/suggest-tests/src/lib.rs
index 8932403ac9f..cc1288c6b72 100644
--- a/src/tools/suggest-tests/src/lib.rs
+++ b/src/tools/suggest-tests/src/lib.rs
@@ -1,7 +1,5 @@
-use std::{
-    fmt::{self, Display},
-    path::Path,
-};
+use std::fmt::{self, Display};
+use std::path::Path;
 
 use dynamic_suggestions::DYNAMIC_SUGGESTIONS;
 use glob::Pattern;
diff --git a/src/tools/suggest-tests/src/static_suggestions.rs b/src/tools/suggest-tests/src/static_suggestions.rs
index a34a4b16ec1..a282facd9df 100644
--- a/src/tools/suggest-tests/src/static_suggestions.rs
+++ b/src/tools/suggest-tests/src/static_suggestions.rs
@@ -1,6 +1,7 @@
-use crate::{sug, Suggestion};
 use std::sync::OnceLock;
 
+use crate::{sug, Suggestion};
+
 // FIXME: perhaps this could use `std::lazy` when it is stablizied
 macro_rules! static_suggestions {
     ($( [ $( $glob:expr ),* $(,)? ] => [ $( $suggestion:expr ),* $(,)? ] ),* $(,)? ) => {
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index 7284feadf9c..14f0a9cd23d 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -1,64 +1,26 @@
 run-make/branch-protection-check-IBT/Makefile
 run-make/cat-and-grep-sanity-check/Makefile
-run-make/cdylib-dylib-linkage/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/dep-info-doesnt-run-much/Makefile
 run-make/dep-info-spaces/Makefile
 run-make/dep-info/Makefile
 run-make/emit-to-stdout/Makefile
 run-make/extern-fn-reachable/Makefile
-run-make/fmt-write-bloat/Makefile
-run-make/foreign-double-unwind/Makefile
-run-make/foreign-exceptions/Makefile
 run-make/incr-add-rust-src-component/Makefile
-run-make/issue-35164/Makefile
-run-make/issue-36710/Makefile
-run-make/issue-47551/Makefile
-run-make/issue-69368/Makefile
 run-make/issue-84395-lto-embed-bitcode/Makefile
-run-make/issue-88756-default-output/Makefile
 run-make/jobserver-error/Makefile
 run-make/libs-through-symlinks/Makefile
 run-make/libtest-json/Makefile
 run-make/libtest-junit/Makefile
 run-make/libtest-thread-limit/Makefile
-run-make/link-cfg/Makefile
-run-make/long-linker-command-lines-cmd-exe/Makefile
-run-make/long-linker-command-lines/Makefile
 run-make/macos-deployment-target/Makefile
 run-make/min-global-align/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/pdb-buildinfo-cl-cmd/Makefile
-run-make/pgo-gen-lto/Makefile
-run-make/pgo-indirect-call-promotion/Makefile
-run-make/print-calling-conventions/Makefile
-run-make/print-target-list/Makefile
-run-make/raw-dylib-alt-calling-convention/Makefile
-run-make/raw-dylib-c/Makefile
-run-make/raw-dylib-import-name-type/Makefile
-run-make/raw-dylib-link-ordinal/Makefile
-run-make/raw-dylib-stdcall-ordinal/Makefile
-run-make/redundant-libs/Makefile
 run-make/remap-path-prefix-dwarf/Makefile
-run-make/reproducible-build-2/Makefile
 run-make/reproducible-build/Makefile
-run-make/rlib-format-packed-bundled-libs-2/Makefile
 run-make/rlib-format-packed-bundled-libs/Makefile
-run-make/share-generics-dylib/Makefile
-run-make/simd-ffi/Makefile
 run-make/split-debuginfo/Makefile
-run-make/stable-symbol-names/Makefile
-run-make/staticlib-dylib-linkage/Makefile
 run-make/symbol-mangling-hashed/Makefile
-run-make/symbol-visibility/Makefile
 run-make/sysroot-crates-are-unstable/Makefile
-run-make/thumb-none-cortex-m/Makefile
-run-make/thumb-none-qemu/Makefile
 run-make/translation/Makefile
 run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile
diff --git a/src/tools/tidy/src/alphabetical/tests.rs b/src/tools/tidy/src/alphabetical/tests.rs
index 560e0284b89..29e89a693bf 100644
--- a/src/tools/tidy/src/alphabetical/tests.rs
+++ b/src/tools/tidy/src/alphabetical/tests.rs
@@ -1,7 +1,8 @@
-use super::*;
 use std::io::Write;
 use std::str::from_utf8;
 
+use super::*;
+
 fn test(lines: &str, name: &str, expected_msg: &str, expected_bad: bool) {
     let mut actual_msg = Vec::new();
     let mut actual_bad = false;
diff --git a/src/tools/tidy/src/bins.rs b/src/tools/tidy/src/bins.rs
index c82e8b6fee9..d158a8e6324 100644
--- a/src/tools/tidy/src/bins.rs
+++ b/src/tools/tidy/src/bins.rs
@@ -21,12 +21,13 @@ mod os_impl {
 
 #[cfg(unix)]
 mod os_impl {
-    use crate::walk::{filter_dirs, walk_no_read};
     use std::fs;
     use std::os::unix::prelude::*;
     use std::path::Path;
     use std::process::{Command, Stdio};
 
+    use crate::walk::{filter_dirs, walk_no_read};
+
     enum FilesystemSupport {
         Supported,
         Unsupported,
diff --git a/src/tools/tidy/src/debug_artifacts.rs b/src/tools/tidy/src/debug_artifacts.rs
index 582014d5059..645534cc827 100644
--- a/src/tools/tidy/src/debug_artifacts.rs
+++ b/src/tools/tidy/src/debug_artifacts.rs
@@ -1,8 +1,9 @@
 //! Tidy check to prevent creation of unnecessary debug artifacts while running tests.
 
-use crate::walk::{filter_dirs, filter_not_rust, walk};
 use std::path::Path;
 
+use crate::walk::{filter_dirs, filter_not_rust, walk};
+
 const GRAPHVIZ_POSTFLOW_MSG: &str = "`borrowck_graphviz_postflow` attribute in test";
 
 pub fn check(test_dir: &Path, bad: &mut bool) {
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 499e735b1df..89011bbb48f 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -1,11 +1,12 @@
 //! 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;
 
+use build_helper::ci::CiEnv;
+use cargo_metadata::{Metadata, Package, PackageId};
+
 /// These are licenses that are allowed for all crates, including the runtime,
 /// rustc, tools, etc.
 #[rustfmt::skip]
@@ -53,6 +54,7 @@ type ExceptionList = &'static [(&'static str, &'static str)];
 pub(crate) const WORKSPACES: &[(&str, ExceptionList, Option<(&[&str], &[&str])>, &[&str])] = &[
     // The root workspace has to be first for check_rustfix to work.
     (".", EXCEPTIONS, Some((&["rustc-main"], PERMITTED_RUSTC_DEPENDENCIES)), &[]),
+    ("library", EXCEPTIONS_STDLIB, Some((&["sysroot"], PERMITTED_STDLIB_DEPENDENCIES)), &[]),
     // Outside of the alphabetical section because rustfmt formats it using multiple lines.
     (
         "compiler/rustc_codegen_cranelift",
@@ -72,7 +74,7 @@ pub(crate) const WORKSPACES: &[(&str, ExceptionList, Option<(&[&str], &[&str])>,
     //("src/tools/miri/test-cargo-miri", &[], None), // FIXME uncomment once all deps are vendored
     //("src/tools/miri/test_dependencies", &[], None), // FIXME uncomment once all deps are vendored
     ("src/tools/rust-analyzer", EXCEPTIONS_RUST_ANALYZER, None, &[]),
-    ("src/tools/rustbook", EXCEPTIONS_RUSTBOOK, None, &["src/doc/book"]),
+    ("src/tools/rustbook", EXCEPTIONS_RUSTBOOK, None, &["src/doc/book", "src/doc/reference"]),
     ("src/tools/rustc-perf", EXCEPTIONS_RUSTC_PERF, None, &["src/tools/rustc-perf"]),
     ("src/tools/x", &[], None, &[]),
     // tidy-alphabetical-end
@@ -89,7 +91,6 @@ const EXCEPTIONS: ExceptionList = &[
     ("colored", "MPL-2.0"),                                  // rustfmt
     ("dissimilar", "Apache-2.0"),                            // rustdoc, rustc_lexer (few tests) via expect-test, (dev deps)
     ("fluent-langneg", "Apache-2.0"),                        // rustc (fluent translations)
-    ("fortanix-sgx-abi", "MPL-2.0"),                         // libstd but only for `sgx` target. FIXME: this dependency violates the documentation comment above.
     ("instant", "BSD-3-Clause"),                             // rustc_driver/tracing-subscriber/parking_lot
     ("mdbook", "MPL-2.0"),                                   // mdbook
     ("option-ext", "MPL-2.0"),                               // cargo-miri (via `directories`)
@@ -107,6 +108,17 @@ const EXCEPTIONS: ExceptionList = &[
     // tidy-alphabetical-end
 ];
 
+/// These are exceptions to Rust's permissive licensing policy, and
+/// should be considered bugs. Exceptions are only allowed in Rust
+/// tooling. It is _crucial_ that no exception crates be dependencies
+/// of the Rust runtime (std/test).
+#[rustfmt::skip]
+const EXCEPTIONS_STDLIB: ExceptionList = &[
+    // tidy-alphabetical-start
+    ("fortanix-sgx-abi", "MPL-2.0"), // libstd but only for `sgx` target. FIXME: this dependency violates the documentation comment above.
+    // tidy-alphabetical-end
+];
+
 // FIXME uncomment once rust-lang/stdarch#1462 lands
 /*
 const EXCEPTIONS_STDARCH: ExceptionList = &[
@@ -180,6 +192,7 @@ const EXCEPTIONS_RUSTBOOK: ExceptionList = &[
 const EXCEPTIONS_CRANELIFT: ExceptionList = &[
     // tidy-alphabetical-start
     ("cranelift-bforest", "Apache-2.0 WITH LLVM-exception"),
+    ("cranelift-bitset", "Apache-2.0 WITH LLVM-exception"),
     ("cranelift-codegen", "Apache-2.0 WITH LLVM-exception"),
     ("cranelift-codegen-meta", "Apache-2.0 WITH LLVM-exception"),
     ("cranelift-codegen-shared", "Apache-2.0 WITH LLVM-exception"),
@@ -227,10 +240,6 @@ const EXCEPTIONS_NON_STANDARD_LICENSE_DEPS: &[&str] = &[
     "ring",
 ];
 
-/// These are the root crates that are part of the runtime. The licenses for
-/// these and all their dependencies *must not* be in the exception list.
-const RUNTIME_CRATES: &[&str] = &["std", "core", "alloc", "test", "panic_abort", "panic_unwind"];
-
 const PERMITTED_DEPS_LOCATION: &str = concat!(file!(), ":", line!());
 
 /// Crates rustc is allowed to depend on. Avoid adding to the list if possible.
@@ -239,7 +248,6 @@ const PERMITTED_DEPS_LOCATION: &str = concat!(file!(), ":", line!());
 /// rustc. Please check with the compiler team before adding an entry.
 const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     // tidy-alphabetical-start
-    "addr2line",
     "adler",
     "ahash",
     "aho-corasick",
@@ -255,7 +263,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "cc",
     "cfg-if",
     "cfg_aliases",
-    "compiler_builtins",
     "cpufeatures",
     "crc32fast",
     "crossbeam-channel",
@@ -275,7 +282,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "digest",
     "displaydoc",
     "dissimilar",
-    "dlmalloc",
     "either",
     "elsa",
     "ena",
@@ -290,7 +296,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "fluent-langneg",
     "fluent-syntax",
     "fnv",
-    "fortanix-sgx-abi",
     "generic-array",
     "getopts",
     "getrandom",
@@ -353,12 +358,9 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "pulldown-cmark-escape",
     "punycode",
     "quote",
-    "r-efi",
-    "r-efi-alloc",
     "rand",
     "rand_chacha",
     "rand_core",
-    "rand_xorshift",
     "rand_xoshiro",
     "redox_syscall",
     "regex",
@@ -428,7 +430,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "unicode-security",
     "unicode-width",
     "unicode-xid",
-    "unwinding",
     "valuable",
     "version_check",
     "wasi",
@@ -462,6 +463,46 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     // tidy-alphabetical-end
 ];
 
+const PERMITTED_STDLIB_DEPENDENCIES: &[&str] = &[
+    // tidy-alphabetical-start
+    "addr2line",
+    "adler",
+    "allocator-api2",
+    "cc",
+    "cfg-if",
+    "compiler_builtins",
+    "dlmalloc",
+    "fortanix-sgx-abi",
+    "getopts",
+    "gimli",
+    "hashbrown",
+    "hermit-abi",
+    "libc",
+    "memchr",
+    "miniz_oxide",
+    "object",
+    "r-efi",
+    "r-efi-alloc",
+    "rand",
+    "rand_core",
+    "rand_xorshift",
+    "rustc-demangle",
+    "unicode-width",
+    "unwinding",
+    "wasi",
+    "windows-sys",
+    "windows-targets",
+    "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",
+    // tidy-alphabetical-end
+];
+
 const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
     // tidy-alphabetical-start
     "ahash",
@@ -471,6 +512,7 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
     "bumpalo",
     "cfg-if",
     "cranelift-bforest",
+    "cranelift-bitset",
     "cranelift-codegen",
     "cranelift-codegen-meta",
     "cranelift-codegen-shared",
@@ -555,9 +597,8 @@ pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
             check_permitted_dependencies(&metadata, workspace, permitted_deps, crates, bad);
         }
 
-        if workspace == "." {
-            let runtime_ids = compute_runtime_crates(&metadata);
-            check_runtime_license_exceptions(&metadata, runtime_ids, bad);
+        if workspace == "library" {
+            check_runtime_license_exceptions(&metadata, bad);
             checked_runtime_licenses = true;
         }
     }
@@ -582,16 +623,8 @@ pub fn has_missing_submodule(root: &Path, submodules: &[&str]) -> bool {
 ///
 /// Unlike for tools we don't allow exceptions to the `LICENSES` list for the runtime with the sole
 /// exception of `fortanix-sgx-abi` which is only used on x86_64-fortanix-unknown-sgx.
-fn check_runtime_license_exceptions(
-    metadata: &Metadata,
-    runtime_ids: HashSet<&PackageId>,
-    bad: &mut bool,
-) {
+fn check_runtime_license_exceptions(metadata: &Metadata, bad: &mut bool) {
     for pkg in &metadata.packages {
-        if !runtime_ids.contains(&pkg.id) {
-            // Only checking dependencies of runtime libraries here.
-            continue;
-        }
         if pkg.source.is_none() {
             // No need to check local packages.
             continue;
@@ -612,20 +645,6 @@ fn check_runtime_license_exceptions(
                 continue;
             }
 
-            // This exception is due to the fact that the feature set of the
-            // `object` crate is different between rustc and libstd. In the
-            // standard library only a conservative set of features are enabled
-            // which notably does not include the `wasm` feature which pulls in
-            // this dependency. In the compiler, however, the `wasm` feature is
-            // enabled. This exception is intended to be here so long as the
-            // `EXCEPTIONS` above contains `wasmparser`, but once that goes away
-            // this can be removed.
-            if pkg.name == "wasmparser"
-                && pkg.license.as_deref() == Some("Apache-2.0 WITH LLVM-exception")
-            {
-                continue;
-            }
-
             tidy_error!(bad, "invalid license `{}` in `{}`", license, pkg.id);
         }
     }
@@ -757,16 +776,6 @@ fn pkg_from_id<'a>(metadata: &'a Metadata, id: &PackageId) -> &'a Package {
     metadata.packages.iter().find(|p| &p.id == id).unwrap()
 }
 
-/// Finds all the packages that are in the rust runtime.
-fn compute_runtime_crates<'a>(metadata: &'a Metadata) -> HashSet<&'a PackageId> {
-    let mut result = HashSet::new();
-    for name in RUNTIME_CRATES {
-        let id = &pkg_from_name(metadata, name).id;
-        deps_of(metadata, id, &mut result);
-    }
-    result
-}
-
 /// Recursively find all dependencies.
 fn deps_of<'a>(metadata: &'a Metadata, pkg_id: &'a PackageId, result: &mut HashSet<&'a PackageId>) {
     if !result.insert(pkg_id) {
diff --git a/src/tools/tidy/src/edition.rs b/src/tools/tidy/src/edition.rs
index f28f677e0ff..6a58d58dbde 100644
--- a/src/tools/tidy/src/edition.rs
+++ b/src/tools/tidy/src/edition.rs
@@ -1,12 +1,8 @@
 //! Tidy check to ensure that crate `edition` is '2018' or '2021'.
 
-use crate::walk::{filter_dirs, walk};
 use std::path::Path;
 
-fn is_edition_2021(mut line: &str) -> bool {
-    line = line.trim();
-    line == "edition = \"2021\""
-}
+use crate::walk::{filter_dirs, walk};
 
 pub fn check(path: &Path, bad: &mut bool) {
     walk(path, |path, _is_dir| filter_dirs(path), &mut |entry, contents| {
@@ -16,8 +12,15 @@ pub fn check(path: &Path, bad: &mut bool) {
             return;
         }
 
-        let is_2021 = contents.lines().any(is_edition_2021);
-        if !is_2021 {
+        let is_2021 = contents.lines().any(|line| line.trim() == "edition = \"2021\"");
+
+        let is_workspace = contents.lines().any(|line| line.trim() == "[workspace]");
+        let is_package = contents.lines().any(|line| line.trim() == "[package]");
+        assert!(is_workspace || is_package);
+
+        // Check that all packages use the 2021 edition. Virtual workspaces don't allow setting an
+        // edition, so these shouldn't be checked.
+        if is_package && !is_2021 {
             tidy_error!(
                 bad,
                 "{} doesn't have `edition = \"2021\"` on a separate line",
diff --git a/src/tools/tidy/src/error_codes.rs b/src/tools/tidy/src/error_codes.rs
index 47e2be761e6..e2d1b85797f 100644
--- a/src/tools/tidy/src/error_codes.rs
+++ b/src/tools/tidy/src/error_codes.rs
@@ -16,7 +16,9 @@
 //! 4. We check that the error code is actually emitted by the compiler.
 //!   - This is done by searching `compiler/` with a regex.
 
-use std::{ffi::OsStr, fs, path::Path};
+use std::ffi::OsStr;
+use std::fs;
+use std::path::Path;
 
 use regex::Regex;
 
@@ -317,7 +319,7 @@ fn check_error_codes_tests(
         if !found_code {
             verbose_print!(
                 verbose,
-                "warning: Error code {code}`` has a UI test file, but doesn't contain its own error code!"
+                "warning: Error code `{code}` has a UI test file, but doesn't contain its own error code!"
             );
         }
     }
diff --git a/src/tools/tidy/src/ext_tool_checks.rs b/src/tools/tidy/src/ext_tool_checks.rs
index 8ce44115ef3..ea9ab01aaf8 100644
--- a/src/tools/tidy/src/ext_tool_checks.rs
+++ b/src/tools/tidy/src/ext_tool_checks.rs
@@ -18,11 +18,9 @@
 //!    is set, rerun the tool to print a suggestion diff (for e.g. CI)
 
 use std::ffi::OsStr;
-use std::fmt;
-use std::fs;
-use std::io;
 use std::path::{Path, PathBuf};
 use std::process::Command;
+use std::{fmt, fs, io};
 
 const MIN_PY_REV: (u32, u32) = (3, 9);
 const MIN_PY_REV_STR: &str = "≥3.9";
diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index e8dff2dc261..a4d27d29d32 100644
--- a/src/tools/tidy/src/features.rs
+++ b/src/tools/tidy/src/features.rs
@@ -9,13 +9,13 @@
 //! * All unstable lang features have tests to ensure they are actually unstable.
 //! * Language features in a group are sorted by feature name.
 
-use crate::walk::{filter_dirs, filter_not_rust, walk, walk_many};
 use std::collections::hash_map::{Entry, HashMap};
 use std::ffi::OsStr;
-use std::fmt;
-use std::fs;
 use std::num::NonZeroU32;
 use std::path::{Path, PathBuf};
+use std::{fmt, fs};
+
+use crate::walk::{filter_dirs, filter_not_rust, walk, walk_many};
 
 #[cfg(test)]
 mod tests;
diff --git a/src/tools/tidy/src/fluent_alphabetical.rs b/src/tools/tidy/src/fluent_alphabetical.rs
index a85367984de..6f154b92eff 100644
--- a/src/tools/tidy/src/fluent_alphabetical.rs
+++ b/src/tools/tidy/src/fluent_alphabetical.rs
@@ -1,11 +1,14 @@
 //! Checks that all Flunt files have messages in alphabetical order
 
-use crate::walk::{filter_dirs, walk};
 use std::collections::HashMap;
-use std::{fs::OpenOptions, io::Write, path::Path};
+use std::fs::OpenOptions;
+use std::io::Write;
+use std::path::Path;
 
 use regex::Regex;
 
+use crate::walk::{filter_dirs, walk};
+
 fn message() -> &'static Regex {
     static_regex!(r#"(?m)^([a-zA-Z0-9_]+)\s*=\s*"#)
 }
diff --git a/src/tools/tidy/src/fluent_period.rs b/src/tools/tidy/src/fluent_period.rs
index 3a1fb6daf48..8bc404dc858 100644
--- a/src/tools/tidy/src/fluent_period.rs
+++ b/src/tools/tidy/src/fluent_period.rs
@@ -1,9 +1,10 @@
 //! Checks that no Fluent messages or attributes end in periods (except ellipses)
 
+use std::path::Path;
+
 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 }
diff --git a/src/tools/tidy/src/fluent_used.rs b/src/tools/tidy/src/fluent_used.rs
index 8b6c6c18813..ab56b5f0b0e 100644
--- a/src/tools/tidy/src/fluent_used.rs
+++ b/src/tools/tidy/src/fluent_used.rs
@@ -1,9 +1,10 @@
 //! Checks that all Fluent messages appear at least twice
 
-use crate::walk::{filter_dirs, walk};
 use std::collections::HashMap;
 use std::path::Path;
 
+use crate::walk::{filter_dirs, walk};
+
 fn filter_used_messages(
     contents: &str,
     msgs_not_appeared_yet: &mut HashMap<String, String>,
diff --git a/src/tools/tidy/src/known_bug.rs b/src/tools/tidy/src/known_bug.rs
index a62556f762b..182a81c6ec9 100644
--- a/src/tools/tidy/src/known_bug.rs
+++ b/src/tools/tidy/src/known_bug.rs
@@ -1,8 +1,9 @@
 //! Tidy check to ensure that tests inside 'tests/crashes' have a '@known-bug' directive.
 
-use crate::walk::*;
 use std::path::Path;
 
+use crate::walk::*;
+
 pub fn check(filepath: &Path, bad: &mut bool) {
     walk(filepath, |path, _is_dir| filter_not_rust(path), &mut |entry, contents| {
         let file = entry.path();
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index ecd32727fa0..3215896091d 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -50,6 +50,7 @@ macro_rules! tidy_error_ext {
 
 fn tidy_error(args: &str) -> std::io::Result<()> {
     use std::io::Write;
+
     use termcolor::{Color, ColorChoice, ColorSpec, StandardStream};
 
     let mut stderr = StandardStream::stdout(ColorChoice::Auto);
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index ec6fc1f07f1..e6d21bfb245 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -4,16 +4,15 @@
 //! etc. This is run by default on `./x.py test` and as part of the auto
 //! builders. The tidy checks can be executed with `./x.py test tidy`.
 
-use tidy::*;
-
 use std::collections::VecDeque;
-use std::env;
 use std::num::NonZeroUsize;
 use std::path::PathBuf;
-use std::process;
 use std::str::FromStr;
 use std::sync::atomic::{AtomicBool, Ordering};
 use std::thread::{self, scope, ScopedJoinHandle};
+use std::{env, process};
+
+use tidy::*;
 
 fn main() {
     // Running Cargo will read the libstd Cargo.toml
diff --git a/src/tools/tidy/src/mir_opt_tests.rs b/src/tools/tidy/src/mir_opt_tests.rs
index 76feeb34331..bb0d8150be4 100644
--- a/src/tools/tidy/src/mir_opt_tests.rs
+++ b/src/tools/tidy/src/mir_opt_tests.rs
@@ -1,9 +1,10 @@
 //! Tidy check to ensure that mir opt directories do not have stale files or dashes in file names
 
-use miropt_test_tools::PanicStrategy;
 use std::collections::HashSet;
 use std::path::{Path, PathBuf};
 
+use miropt_test_tools::PanicStrategy;
+
 use crate::walk::walk_no_read;
 
 fn check_unused_files(path: &Path, bless: bool, bad: &mut bool) {
diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs
index 2f8abc77566..b7ddf47186d 100644
--- a/src/tools/tidy/src/pal.rs
+++ b/src/tools/tidy/src/pal.rs
@@ -30,9 +30,10 @@
 //! platform-specific cfgs are allowed. Not sure yet how to deal with
 //! this in the long term.
 
-use crate::walk::{filter_dirs, walk};
 use std::path::Path;
 
+use crate::walk::{filter_dirs, walk};
+
 // Paths that may contain platform-specific code.
 const EXCEPTION_PATHS: &[&str] = &[
     "library/panic_abort",
diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs
index 8d8cc7ad6d3..6394a1463b0 100644
--- a/src/tools/tidy/src/style.rs
+++ b/src/tools/tidy/src/style.rs
@@ -17,10 +17,14 @@
 //! `// ignore-tidy-CHECK-NAME`.
 // ignore-tidy-dbg
 
-use crate::walk::{filter_dirs, walk};
+use std::ffi::OsStr;
+use std::path::Path;
+use std::sync::LazyLock;
+
 use regex::RegexSetBuilder;
 use rustc_hash::FxHashMap;
-use std::{ffi::OsStr, path::Path, sync::LazyLock};
+
+use crate::walk::{filter_dirs, walk};
 
 #[cfg(test)]
 mod tests;
diff --git a/src/tools/tidy/src/target_policy.rs b/src/tools/tidy/src/target_policy.rs
index cb9a0c1c7f4..776221d3062 100644
--- a/src/tools/tidy/src/target_policy.rs
+++ b/src/tools/tidy/src/target_policy.rs
@@ -2,8 +2,10 @@
 //!
 //! As of writing, only checks that sanity-check assembly test for targets doesn't miss any targets.
 
+use std::collections::HashSet;
+use std::path::Path;
+
 use crate::walk::{filter_not_rust, walk};
-use std::{collections::HashSet, path::Path};
 
 const TARGET_DEFINITIONS_PATH: &str = "compiler/rustc_target/src/spec/targets/";
 const ASSEMBLY_TEST_PATH: &str = "tests/assembly/targets/";
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 0ae0356b2c4..41f7778c952 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -2,13 +2,14 @@
 //! - 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;
 use std::fs;
 use std::io::Write;
 use std::path::{Path, PathBuf};
 
+use ignore::Walk;
+
 // FIXME: GitHub's UI truncates file lists that exceed 1000 entries, so these
 // 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
diff --git a/src/tools/tidy/src/unit_tests.rs b/src/tools/tidy/src/unit_tests.rs
index 0a5dad88789..708e4ef8085 100644
--- a/src/tools/tidy/src/unit_tests.rs
+++ b/src/tools/tidy/src/unit_tests.rs
@@ -7,9 +7,10 @@
 //! named `tests.rs` or `benches.rs`, or directories named `tests` or `benches` unconfigured
 //! during normal build.
 
-use crate::walk::{filter_dirs, walk};
 use std::path::Path;
 
+use crate::walk::{filter_dirs, walk};
+
 pub fn check(root_path: &Path, bad: &mut bool) {
     let core = root_path.join("core");
     let core_copy = core.clone();
diff --git a/src/tools/tidy/src/unstable_book.rs b/src/tools/tidy/src/unstable_book.rs
index 7dfb6224d24..8be25b98df0 100644
--- a/src/tools/tidy/src/unstable_book.rs
+++ b/src/tools/tidy/src/unstable_book.rs
@@ -1,8 +1,9 @@
-use crate::features::{CollectedFeatures, Features, Status};
 use std::collections::BTreeSet;
 use std::fs;
 use std::path::{Path, PathBuf};
 
+use crate::features::{CollectedFeatures, Features, Status};
+
 pub const PATH_STR: &str = "doc/unstable-book";
 
 pub const COMPILER_FLAGS_DIR: &str = "src/compiler-flags";
diff --git a/src/tools/tidy/src/walk.rs b/src/tools/tidy/src/walk.rs
index 1cecf998e28..d4721b5a5fd 100644
--- a/src/tools/tidy/src/walk.rs
+++ b/src/tools/tidy/src/walk.rs
@@ -1,6 +1,9 @@
-use ignore::DirEntry;
+use std::ffi::OsStr;
+use std::fs::File;
+use std::io::Read;
+use std::path::Path;
 
-use std::{ffi::OsStr, fs::File, io::Read, path::Path};
+use ignore::DirEntry;
 
 /// The default directory filter.
 pub fn filter_dirs(path: &Path) -> bool {
diff --git a/src/tools/tidy/src/x_version.rs b/src/tools/tidy/src/x_version.rs
index 55bfbed8b0e..489343561e1 100644
--- a/src/tools/tidy/src/x_version.rs
+++ b/src/tools/tidy/src/x_version.rs
@@ -1,7 +1,8 @@
-use semver::Version;
 use std::path::Path;
 use std::process::{Command, Stdio};
 
+use semver::Version;
+
 pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
     let cargo_list = Command::new(cargo).args(["install", "--list"]).stdout(Stdio::piped()).spawn();
 
diff --git a/src/tools/unicode-table-generator/src/cascading_map.rs b/src/tools/unicode-table-generator/src/cascading_map.rs
index 02c7542309a..036f0bd7eac 100644
--- a/src/tools/unicode-table-generator/src/cascading_map.rs
+++ b/src/tools/unicode-table-generator/src/cascading_map.rs
@@ -1,9 +1,10 @@
-use crate::fmt_list;
-use crate::raw_emitter::RawEmitter;
 use std::collections::HashMap;
 use std::fmt::Write as _;
 use std::ops::Range;
 
+use crate::fmt_list;
+use crate::raw_emitter::RawEmitter;
+
 impl RawEmitter {
     pub fn emit_cascading_map(&mut self, ranges: &[Range<u32>]) -> bool {
         let mut map: [u8; 256] = [
diff --git a/src/tools/unicode-table-generator/src/case_mapping.rs b/src/tools/unicode-table-generator/src/case_mapping.rs
index 7a978db62b4..f28161c7829 100644
--- a/src/tools/unicode-table-generator/src/case_mapping.rs
+++ b/src/tools/unicode-table-generator/src/case_mapping.rs
@@ -1,9 +1,8 @@
+use std::char;
+use std::collections::BTreeMap;
+use std::fmt::{self, Write};
+
 use crate::{fmt_list, UnicodeData};
-use std::{
-    char,
-    collections::BTreeMap,
-    fmt::{self, Write},
-};
 
 const INDEX_MASK: u32 = 1 << 22;
 
diff --git a/src/tools/unicode-table-generator/src/main.rs b/src/tools/unicode-table-generator/src/main.rs
index 2fe578acd90..9f89e7c33f7 100644
--- a/src/tools/unicode-table-generator/src/main.rs
+++ b/src/tools/unicode-table-generator/src/main.rs
@@ -73,6 +73,7 @@
 
 use std::collections::{BTreeMap, HashMap};
 use std::ops::Range;
+
 use ucd_parse::Codepoints;
 
 mod cascading_map;
diff --git a/src/tools/unicode-table-generator/src/raw_emitter.rs b/src/tools/unicode-table-generator/src/raw_emitter.rs
index ef5cea18ea2..47120e4f169 100644
--- a/src/tools/unicode-table-generator/src/raw_emitter.rs
+++ b/src/tools/unicode-table-generator/src/raw_emitter.rs
@@ -1,8 +1,9 @@
-use crate::fmt_list;
 use std::collections::{BTreeMap, BTreeSet, HashMap};
 use std::fmt::{self, Write};
 use std::ops::Range;
 
+use crate::fmt_list;
+
 #[derive(Clone)]
 pub struct RawEmitter {
     pub file: String,
diff --git a/src/tools/unicode-table-generator/src/skiplist.rs b/src/tools/unicode-table-generator/src/skiplist.rs
index 8fae8289e25..8ca18ddc91a 100644
--- a/src/tools/unicode-table-generator/src/skiplist.rs
+++ b/src/tools/unicode-table-generator/src/skiplist.rs
@@ -1,8 +1,9 @@
-use crate::fmt_list;
-use crate::raw_emitter::RawEmitter;
 use std::fmt::Write as _;
 use std::ops::Range;
 
+use crate::fmt_list;
+use crate::raw_emitter::RawEmitter;
+
 /// This will get packed into a single u32 before inserting into the data set.
 #[derive(Debug, PartialEq)]
 struct ShortOffsetRunHeader {
diff --git a/src/tools/unicode-table-generator/src/unicode_download.rs b/src/tools/unicode-table-generator/src/unicode_download.rs
index 714bb53382e..c9826170905 100644
--- a/src/tools/unicode-table-generator/src/unicode_download.rs
+++ b/src/tools/unicode-table-generator/src/unicode_download.rs
@@ -1,7 +1,8 @@
-use crate::UNICODE_DIRECTORY;
 use std::path::Path;
 use std::process::{Command, Output};
 
+use crate::UNICODE_DIRECTORY;
+
 static URL_PREFIX: &str = "https://www.unicode.org/Public/UCD/latest/ucd/";
 
 static README: &str = "ReadMe.txt";
diff --git a/src/tools/unstable-book-gen/src/main.rs b/src/tools/unstable-book-gen/src/main.rs
index a9830a3840d..9af8802b012 100644
--- a/src/tools/unstable-book-gen/src/main.rs
+++ b/src/tools/unstable-book-gen/src/main.rs
@@ -4,6 +4,7 @@ use std::collections::BTreeSet;
 use std::env;
 use std::fs::{self, write};
 use std::path::Path;
+
 use tidy::features::{collect_lang_features, collect_lib_features, Features};
 use tidy::t;
 use tidy::unstable_book::{
diff --git a/src/tools/x/src/main.rs b/src/tools/x/src/main.rs
index 5da8a2888ec..b288cfcd5be 100644
--- a/src/tools/x/src/main.rs
+++ b/src/tools/x/src/main.rs
@@ -8,12 +8,11 @@
 //! the ones that call `x.py`. We use `sh -c` on Unix, because it is a standard.
 //! We also don't use `pwsh` on Windows, because it is not installed by default;
 
-use std::{
-    env::{self, consts::EXE_EXTENSION},
-    io,
-    path::Path,
-    process::{self, Command, ExitStatus},
-};
+use std::env::consts::EXE_EXTENSION;
+use std::env::{self};
+use std::io;
+use std::path::Path;
+use std::process::{self, Command, ExitStatus};
 
 const PYTHON: &str = "python";
 const PYTHON2: &str = "python2";